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;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.GuardedBy;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.dom.api.DOMDataBroker;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
37 import org.opendaylight.mdsal.common.api.CommitInfo;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
39 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
40 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
41 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
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.policy.BGPRibRoutingPolicy;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
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.Route;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpId;
66 import org.opendaylight.yangtools.yang.binding.ChildOf;
67 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
68 import org.opendaylight.yangtools.yang.binding.DataObject;
69 import org.opendaylight.yangtools.yang.binding.Identifiable;
70 import org.opendaylight.yangtools.yang.binding.Identifier;
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.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.model.api.SchemaContext;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
87 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
88 SchemaContextListener, AutoCloseable {
89 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
90 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
92 private final BGPDispatcher dispatcher;
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 DataBroker dataBroker;
99 private final RIBExtensionConsumerContext extensions;
100 private final YangInstanceIdentifier yangRibId;
101 private final RIBSupportContextRegistryImpl ribContextRegistry;
102 private final CodecsRegistryImpl codecsRegistry;
103 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
104 private final DOMDataBrokerExtension domService;
105 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
106 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
107 private final RibId ribId;
108 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
109 private final BGPRibRoutingPolicy ribPolicies;
111 private ClusterSingletonServiceRegistration registration;
113 private DOMTransactionChain domChain;
115 private boolean isServiceInstantiated;
116 private final Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
119 final BGPTableTypeRegistryConsumer tableTypeRegistry,
121 final AsNumber localAs,
122 final BgpId localBgpId,
123 final RIBExtensionConsumerContext extensions,
124 final BGPDispatcher dispatcher,
125 final CodecsRegistryImpl codecsRegistry,
126 final DOMDataBroker domDataBroker,
127 final DataBroker dataBroker,
128 final BGPRibRoutingPolicy ribPolicies,
129 final List<BgpTableType> localTables,
130 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
132 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
133 localBgpId, localAs);
134 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
135 this.localAs = requireNonNull(localAs);
136 this.bgpIdentifier = requireNonNull(localBgpId);
137 this.dispatcher = requireNonNull(dispatcher);
138 this.localTables = ImmutableSet.copyOf(localTables);
139 this.localTablesKeys = new HashSet<>();
140 this.domDataBroker = requireNonNull(domDataBroker);
141 this.dataBroker = requireNonNull(dataBroker);
142 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
143 this.extensions = requireNonNull(extensions);
144 this.ribPolicies = requireNonNull(ribPolicies);
145 this.codecsRegistry = codecsRegistry;
146 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
147 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME)
149 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
150 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
153 for (final BgpTableType t : this.localTables) {
154 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
155 this.localTablesKeys.add(key);
159 private synchronized void startLocRib(final TablesKey key) {
160 LOG.debug("Creating LocRib table for {}", key);
161 // create locRibWriter for each table
162 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
164 final RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
165 if (ribSupport != null) {
166 final MapEntryNode emptyTable = ribSupport.emptyTable();
167 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
168 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME)).node(emptyTable.getIdentifier());
170 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
173 } catch (final InterruptedException | ExecutionException e1) {
174 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
177 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
181 private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
182 R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
183 void createLocRibWriter(final TablesKey key) {
184 final RIBSupport<C, S, R, I> ribSupport = this.ribContextRegistry.getRIBSupport(key);
185 if (ribSupport == null) {
188 LOG.debug("Creating LocRIB writer for key {}", key);
189 final BindingTransactionChain txChain = createPeerChain(this);
190 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
191 if (pathSelectionStrategy == null) {
192 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
195 final LocRibWriter locRibWriter = LocRibWriter.create(
198 this.tableTypeRegistry.getAfiSafiType(key).get(),
200 getInstanceIdentifier(),
205 pathSelectionStrategy);
206 this.vpnTableRefresher.put(key, locRibWriter);
207 registerTotalPathCounter(key, locRibWriter);
208 registerTotalPrefixesCounter(key, locRibWriter);
209 this.txChainToLocRibWriter.put(txChain, locRibWriter);
213 public String toString() {
214 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
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,
248 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
249 LOG.error("Broken chain in RIB {} transaction {}",
250 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
251 if (this.txChainToLocRibWriter.containsKey(chain)) {
252 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
253 final BindingTransactionChain newChain = createPeerChain(this);
254 startLocRib(locRibWriter.getTableKey());
255 locRibWriter.restart(newChain);
256 this.txChainToLocRibWriter.put(newChain, locRibWriter);
261 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
262 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
266 public Set<TablesKey> getLocalTablesKeys() {
267 return this.localTablesKeys;
271 public boolean supportsTable(final TablesKey tableKey) {
272 return this.localTablesKeys.contains(tableKey);
276 public BGPRibRoutingPolicy getRibPolicies() {
277 return this.ribPolicies;
281 public BGPPeerTracker getPeerTracker() {
282 return this.peerTracker;
286 public void refreshTable(final TablesKey tk, final PeerId peerId) {
287 final RibOutRefresh table = this.vpnTableRefresher.get(tk);
289 table.refreshTable(tk, peerId);
294 public DOMDataTreeChangeService getService() {
295 return (DOMDataTreeChangeService) this.domService;
299 public DataBroker getDataBroker() {
300 return this.dataBroker;
304 public YangInstanceIdentifier getYangRibId() {
305 return this.yangRibId;
309 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
310 return this.dataBroker.createTransactionChain(listener);
314 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
315 return this.domDataBroker.createTransactionChain(listener);
319 public RIBExtensionConsumerContext getRibExtensions() {
320 return this.extensions;
324 public RIBSupportContextRegistry getRibSupportContext() {
325 return this.ribContextRegistry;
329 public void onGlobalContextUpdated(final SchemaContext context) {
330 this.codecsRegistry.onSchemaContextUpdated(context);
334 public CodecsRegistry getCodecsRegistry() {
335 return this.codecsRegistry;
338 public synchronized void instantiateServiceInstance() {
339 this.isServiceInstantiated = true;
341 this.domChain = this.domDataBroker.createTransactionChain(this);
342 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
344 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
345 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
347 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
348 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
349 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
350 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
351 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
352 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
355 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
357 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
358 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(),
360 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
363 trans.commit().get();
364 } catch (final InterruptedException | ExecutionException e) {
365 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
368 LOG.debug("Effective RIB created.");
370 this.localTablesKeys.forEach(this::startLocRib);
371 this.localTablesKeys.forEach(this::createLocRibWriter);
374 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
375 if (!this.isServiceInstantiated) {
376 LOG.trace("RIB {} already closed", this.ribId.getValue());
377 return CommitInfo.emptyFluentFuture();
379 LOG.info("Close RIB {}", this.ribId.getValue());
380 this.isServiceInstantiated = false;
383 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
384 this.txChainToLocRibWriter.clear();
386 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
387 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
388 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
389 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
391 public void onSuccess(final CommitInfo result) {
392 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
396 public void onFailure(final Throwable throwable) {
397 LOG.error("Failed to clean RIB {}",
398 RIBImpl.this.ribId.getValue(), throwable);
400 }, MoreExecutors.directExecutor());
401 this.domChain.close();