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.RIBSupportContext;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
53 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
54 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
55 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
56 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
57 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.common.QName;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
76 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
79 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
80 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
81 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
83 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 public final class RIBImpl extends BGPRIBStateImpl implements ClusterSingletonService, RIB, TransactionChainListener,
89 SchemaContextListener, AutoCloseable {
90 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
91 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
92 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 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 Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
110 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
111 private final ImportPolicyPeerTracker importPolicyPeerTracker;
112 private final RibId ribId;
113 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
115 private DOMTransactionChain domChain;
117 private boolean isServiceInstantiated;
119 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
120 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
121 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
122 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
123 final BgpDeployer.WriteConfiguration configurationWriter) {
124 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
125 localBgpId, localAs);
126 this.localAs = requireNonNull(localAs);
127 this.bgpIdentifier = requireNonNull(localBgpId);
128 this.dispatcher = requireNonNull(dispatcher);
129 this.localTables = ImmutableSet.copyOf(localTables);
130 this.localTablesKeys = new HashSet<>();
131 this.domDataBroker = requireNonNull(domDataBroker);
132 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
133 this.extensions = requireNonNull(extensions);
134 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
135 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
136 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
137 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
138 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
139 final ClusterIdentifier cId = clusterId == null ? new ClusterIdentifier(localBgpId) : clusterId;
141 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
142 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
143 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
144 requireNonNull(provider, "ClusterSingletonServiceProvider is null");
145 this.provider = provider;
146 this.configurationWriter = configurationWriter;
148 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
149 for (final BgpTableType t : this.localTables) {
150 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
151 this.localTablesKeys.add(key);
152 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
154 this.exportPolicyPeerTrackerMap = exportPolicies.build();
155 LOG.info("RIB Singleton Service {} registered, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
156 //this need to be always the last step
157 this.registration = registerClusterSingletonService(this);
160 private void startLocRib(final TablesKey key) {
161 LOG.debug("Creating LocRib table for {}", key);
162 // create locRibWriter for each table
163 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
165 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
166 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
167 table.withChild(EMPTY_TABLE_ATTRIBUTES);
169 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
170 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
171 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
172 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
173 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
176 final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
177 if (supportContext != null) {
178 final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
179 table.withChild(routes);
181 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
183 tx.submit().checkedGet();
184 } catch (final TransactionCommitFailedException e1) {
185 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
187 createLocRibWriter(key);
189 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
193 private synchronized void createLocRibWriter(final TablesKey key) {
194 LOG.debug("Creating LocRIB writer for key {}", key);
195 final DOMTransactionChain txChain = createPeerChain(this);
196 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
197 if (pathSelectionStrategy == null) {
198 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
201 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
202 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
203 registerTotalPathCounter(key, locRibWriter);
204 registerTotalPrefixesCounter(key, locRibWriter);
205 this.txChainToLocRibWriter.put(txChain, locRibWriter);
209 public String toString() {
210 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
213 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
214 return toStringHelper;
218 public synchronized void close() throws Exception {
219 if (this.registration != null) {
220 this.registration.close();
221 this.registration = null;
226 public AsNumber getLocalAs() {
231 public BgpId getBgpIdentifier() {
232 return this.bgpIdentifier;
237 public Set<? extends BgpTableType> getLocalTables() {
238 return this.localTables;
242 public BGPDispatcher getDispatcher() {
243 return this.dispatcher;
247 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
248 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
249 if (this.txChainToLocRibWriter.containsKey(chain)) {
250 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
251 final DOMTransactionChain newChain = createPeerChain(this);
252 locRibWriter.restart(newChain);
253 this.txChainToLocRibWriter.put(newChain, locRibWriter);
258 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
259 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
263 public Set<TablesKey> getLocalTablesKeys() {
264 return this.localTablesKeys;
268 public DOMDataTreeChangeService getService() {
269 return (DOMDataTreeChangeService) this.service;
273 public YangInstanceIdentifier getYangRibId() {
274 return this.yangRibId;
278 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
279 return this.domDataBroker.createTransactionChain(listener);
283 public RIBExtensionConsumerContext getRibExtensions() {
284 return this.extensions;
288 public RIBSupportContextRegistry getRibSupportContext() {
289 return this.ribContextRegistry;
293 public void onGlobalContextUpdated(final SchemaContext context) {
294 this.codecsRegistry.onSchemaContextUpdated(context);
298 public CodecsRegistry getCodecsRegistry() {
299 return this.codecsRegistry;
303 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
304 return this.importPolicyPeerTracker;
308 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
309 return this.exportPolicyPeerTrackerMap.get(tablesKey);
313 public synchronized void instantiateServiceInstance() {
314 this.isServiceInstantiated = true;
315 this.domChain = this.domDataBroker.createTransactionChain(this);
316 if (this.configurationWriter != null) {
317 this.configurationWriter.apply();
319 LOG.info("RIB Singleton Service {} instantiated, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
320 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
322 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
323 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
325 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
326 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
327 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
328 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
329 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
330 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
334 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
336 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
337 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
338 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
341 trans.submit().checkedGet();
342 } catch (final TransactionCommitFailedException e) {
343 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
346 LOG.debug("Effective RIB created.");
348 this.localTablesKeys.forEach(this::startLocRib);
352 public synchronized ListenableFuture<Void> closeServiceInstance() {
353 if (!this.isServiceInstantiated) {
354 LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
355 this.ribId.getValue());
356 return Futures.immediateFuture(null);
358 LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
359 this.isServiceInstantiated = false;
361 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
362 this.txChainToLocRibWriter.clear();
364 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
365 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
366 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
368 this.domChain.close();
373 public ServiceGroupIdentifier getIdentifier() {
374 return this.serviceGroupIdentifier;
378 public ClusterSingletonServiceRegistration registerClusterSingletonService(
379 final ClusterSingletonService clusterSingletonService) {
380 return ClusterSingletonServiceRegistrationHelper
381 .registerSingletonService(this.provider, clusterSingletonService);
385 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
386 return getIdentifier();