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.collect.ImmutableSet;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
21 import java.util.Map.Entry;
23 import java.util.concurrent.ExecutionException;
24 import javax.annotation.Nonnull;
25 import javax.annotation.concurrent.GuardedBy;
26 import javax.annotation.concurrent.ThreadSafe;
27 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
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.common.api.CommitInfo;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
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.openconfig.spi.BGPTableTypeRegistryConsumer;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
48 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
49 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
51 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
52 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpId;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.QName;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
71 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
74 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
75 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
76 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
78 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
84 SchemaContextListener, AutoCloseable {
85 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
86 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
87 private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang
88 .gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Attributes.QNAME);
90 private final BGPDispatcher dispatcher;
91 private final AsNumber localAs;
92 private final BgpId bgpIdentifier;
93 private final Set<BgpTableType> localTables;
94 private final Set<TablesKey> localTablesKeys;
95 private final DOMDataBroker domDataBroker;
96 private final DataBroker dataBroker;
97 private final RIBExtensionConsumerContext extensions;
98 private final YangInstanceIdentifier yangRibId;
99 private final RIBSupportContextRegistryImpl ribContextRegistry;
100 private final CodecsRegistryImpl codecsRegistry;
101 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
102 private final DOMDataBrokerExtension domService;
103 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
104 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
105 private final RibId ribId;
106 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
107 private final BGPRibRoutingPolicy ribPolicies;
109 private ClusterSingletonServiceRegistration registration;
111 private DOMTransactionChain domChain;
113 private boolean isServiceInstantiated;
116 final BGPTableTypeRegistryConsumer tableTypeRegistry,
118 final AsNumber localAs,
119 final BgpId localBgpId,
120 final RIBExtensionConsumerContext extensions,
121 final BGPDispatcher dispatcher,
122 final CodecsRegistryImpl codecsRegistry,
123 final DOMDataBroker domDataBroker,
124 final DataBroker dataBroker,
125 final BGPRibRoutingPolicy ribPolicies,
126 final List<BgpTableType> localTables,
127 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
129 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
130 localBgpId, localAs);
131 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
132 this.localAs = requireNonNull(localAs);
133 this.bgpIdentifier = requireNonNull(localBgpId);
134 this.dispatcher = requireNonNull(dispatcher);
135 this.localTables = ImmutableSet.copyOf(localTables);
136 this.localTablesKeys = new HashSet<>();
137 this.domDataBroker = requireNonNull(domDataBroker);
138 this.dataBroker = requireNonNull(dataBroker);
139 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
140 this.extensions = requireNonNull(extensions);
141 this.ribPolicies = requireNonNull(ribPolicies);
142 this.codecsRegistry = codecsRegistry;
143 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
144 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
145 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
146 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
149 for (final BgpTableType t : this.localTables) {
150 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
151 this.localTablesKeys.add(key);
155 private synchronized void startLocRib(final TablesKey key) {
156 LOG.debug("Creating LocRib table for {}", key);
157 // create locRibWriter for each table
158 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
160 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
161 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
162 table.withChild(EMPTY_TABLE_ATTRIBUTES);
164 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
165 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
166 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
167 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
168 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
169 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
172 final RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
173 if (ribSupport != null) {
174 final ChoiceNode routes = ribSupport.emptyRoutes();
175 table.withChild(routes);
177 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
180 } catch (final InterruptedException | ExecutionException e1) {
181 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
184 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
188 private synchronized void createLocRibWriter(final TablesKey key) {
189 final RIBSupport<?, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
190 if (ribSupport == null) {
193 LOG.debug("Creating LocRIB writer for key {}", key);
194 final BindingTransactionChain txChain = createPeerChain(this);
195 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
196 if (pathSelectionStrategy == null) {
197 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
200 final LocRibWriter locRibWriter = LocRibWriter.create(
203 this.tableTypeRegistry.getAfiSafiType(key).get(),
205 getInstanceIdentifier(),
210 pathSelectionStrategy);
211 registerTotalPathCounter(key, locRibWriter);
212 registerTotalPrefixesCounter(key, locRibWriter);
213 this.txChainToLocRibWriter.put(txChain, locRibWriter);
217 public String toString() {
218 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
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 synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
252 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
253 LOG.error("Broken chain in RIB {} transaction {}",
254 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
255 if (this.txChainToLocRibWriter.containsKey(chain)) {
256 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
257 final BindingTransactionChain newChain = createPeerChain(this);
258 startLocRib(locRibWriter.getTableKey());
259 locRibWriter.restart(newChain);
260 this.txChainToLocRibWriter.put(newChain, locRibWriter);
265 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
266 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
270 public Set<TablesKey> getLocalTablesKeys() {
271 return this.localTablesKeys;
275 public boolean supportsTable(final TablesKey tableKey) {
276 return this.localTablesKeys.contains(tableKey);
280 public BGPRibRoutingPolicy getRibPolicies() {
281 return this.ribPolicies;
285 public BGPPeerTracker getPeerTracker() {
286 return this.peerTracker;
290 public DOMDataTreeChangeService getService() {
291 return (DOMDataTreeChangeService) this.domService;
295 public DataBroker getDataBroker() {
296 return this.dataBroker;
300 public YangInstanceIdentifier getYangRibId() {
301 return this.yangRibId;
305 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
306 return this.dataBroker.createTransactionChain(listener);
310 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
311 return this.domDataBroker.createTransactionChain(listener);
315 public RIBExtensionConsumerContext getRibExtensions() {
316 return this.extensions;
320 public RIBSupportContextRegistry getRibSupportContext() {
321 return this.ribContextRegistry;
325 public void onGlobalContextUpdated(final SchemaContext context) {
326 this.codecsRegistry.onSchemaContextUpdated(context);
330 public CodecsRegistry getCodecsRegistry() {
331 return this.codecsRegistry;
334 public synchronized void instantiateServiceInstance() {
335 this.isServiceInstantiated = true;
337 this.domChain = this.domDataBroker.createTransactionChain(this);
338 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
340 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
341 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
343 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
344 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
345 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
346 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
347 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
348 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
352 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
354 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
355 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
356 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
359 trans.commit().get();
360 } catch (final InterruptedException | ExecutionException e) {
361 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
364 LOG.debug("Effective RIB created.");
366 this.localTablesKeys.forEach(this::startLocRib);
367 this.localTablesKeys.forEach(this::createLocRibWriter);
370 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
371 if (!this.isServiceInstantiated) {
372 LOG.trace("RIB {} already closed", this.ribId.getValue());
373 return CommitInfo.emptyFluentFuture();
375 LOG.info("Close RIB {}", this.ribId.getValue());
376 this.isServiceInstantiated = false;
379 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
380 this.txChainToLocRibWriter.clear();
382 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
383 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
384 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
385 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
387 public void onSuccess(final CommitInfo result) {
388 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
392 public void onFailure(final Throwable throwable) {
393 LOG.error("Failed to clean RIB {}",
394 RIBImpl.this.ribId.getValue(), throwable);
396 }, MoreExecutors.directExecutor());
397 this.domChain.close();