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.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.ContainerNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
73 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
74 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
82 SchemaContextListener, AutoCloseable {
83 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
84 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
86 private final BGPDispatcher dispatcher;
87 private final AsNumber localAs;
88 private final BgpId bgpIdentifier;
89 private final Set<BgpTableType> localTables;
90 private final Set<TablesKey> localTablesKeys;
91 private final DOMDataBroker domDataBroker;
92 private final DataBroker dataBroker;
93 private final RIBExtensionConsumerContext extensions;
94 private final YangInstanceIdentifier yangRibId;
95 private final RIBSupportContextRegistryImpl ribContextRegistry;
96 private final CodecsRegistryImpl codecsRegistry;
97 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
98 private final DOMDataBrokerExtension domService;
99 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
100 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
101 private final RibId ribId;
102 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
103 private final BGPRibRoutingPolicy ribPolicies;
105 private ClusterSingletonServiceRegistration registration;
107 private DOMTransactionChain domChain;
109 private boolean isServiceInstantiated;
110 private Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
113 final BGPTableTypeRegistryConsumer tableTypeRegistry,
115 final AsNumber localAs,
116 final BgpId localBgpId,
117 final RIBExtensionConsumerContext extensions,
118 final BGPDispatcher dispatcher,
119 final CodecsRegistryImpl codecsRegistry,
120 final DOMDataBroker domDataBroker,
121 final DataBroker dataBroker,
122 final BGPRibRoutingPolicy ribPolicies,
123 final List<BgpTableType> localTables,
124 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
126 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
127 localBgpId, localAs);
128 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
129 this.localAs = requireNonNull(localAs);
130 this.bgpIdentifier = requireNonNull(localBgpId);
131 this.dispatcher = requireNonNull(dispatcher);
132 this.localTables = ImmutableSet.copyOf(localTables);
133 this.localTablesKeys = new HashSet<>();
134 this.domDataBroker = requireNonNull(domDataBroker);
135 this.dataBroker = requireNonNull(dataBroker);
136 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
137 this.extensions = requireNonNull(extensions);
138 this.ribPolicies = requireNonNull(ribPolicies);
139 this.codecsRegistry = codecsRegistry;
140 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
141 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
142 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
143 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
146 for (final BgpTableType t : this.localTables) {
147 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
148 this.localTablesKeys.add(key);
152 private synchronized void startLocRib(final TablesKey key) {
153 LOG.debug("Creating LocRib table for {}", key);
154 // create locRibWriter for each table
155 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
157 final RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
158 if (ribSupport != null) {
159 final MapEntryNode emptyTable = ribSupport.emptyTable();
160 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
161 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME)).node(emptyTable.getIdentifier());
163 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
166 } catch (final InterruptedException | ExecutionException e1) {
167 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
170 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
174 private synchronized void createLocRibWriter(final TablesKey key) {
175 final RIBSupport<?, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
176 if (ribSupport == null) {
179 LOG.debug("Creating LocRIB writer for key {}", key);
180 final BindingTransactionChain txChain = createPeerChain(this);
181 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
182 if (pathSelectionStrategy == null) {
183 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
186 final LocRibWriter locRibWriter = LocRibWriter.create(
189 this.tableTypeRegistry.getAfiSafiType(key).get(),
191 getInstanceIdentifier(),
196 pathSelectionStrategy);
197 this.vpnTableRefresher.put(key, locRibWriter);
198 registerTotalPathCounter(key, locRibWriter);
199 registerTotalPrefixesCounter(key, locRibWriter);
200 this.txChainToLocRibWriter.put(txChain, locRibWriter);
204 public String toString() {
205 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
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 synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
239 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
240 LOG.error("Broken chain in RIB {} transaction {}",
241 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
242 if (this.txChainToLocRibWriter.containsKey(chain)) {
243 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
244 final BindingTransactionChain newChain = createPeerChain(this);
245 startLocRib(locRibWriter.getTableKey());
246 locRibWriter.restart(newChain);
247 this.txChainToLocRibWriter.put(newChain, locRibWriter);
252 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
253 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
257 public Set<TablesKey> getLocalTablesKeys() {
258 return this.localTablesKeys;
262 public boolean supportsTable(final TablesKey tableKey) {
263 return this.localTablesKeys.contains(tableKey);
267 public BGPRibRoutingPolicy getRibPolicies() {
268 return this.ribPolicies;
272 public BGPPeerTracker getPeerTracker() {
273 return this.peerTracker;
277 public void refreshTable(final TablesKey tk, final PeerId peerId) {
278 this.vpnTableRefresher.get(tk).refreshTable(tk, peerId);
282 public DOMDataTreeChangeService getService() {
283 return (DOMDataTreeChangeService) this.domService;
287 public DataBroker getDataBroker() {
288 return this.dataBroker;
292 public YangInstanceIdentifier getYangRibId() {
293 return this.yangRibId;
297 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
298 return this.dataBroker.createTransactionChain(listener);
302 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
303 return this.domDataBroker.createTransactionChain(listener);
307 public RIBExtensionConsumerContext getRibExtensions() {
308 return this.extensions;
312 public RIBSupportContextRegistry getRibSupportContext() {
313 return this.ribContextRegistry;
317 public void onGlobalContextUpdated(final SchemaContext context) {
318 this.codecsRegistry.onSchemaContextUpdated(context);
322 public CodecsRegistry getCodecsRegistry() {
323 return this.codecsRegistry;
326 public synchronized void instantiateServiceInstance() {
327 this.isServiceInstantiated = true;
329 this.domChain = this.domDataBroker.createTransactionChain(this);
330 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
332 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
333 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
335 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
336 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
337 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
338 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
339 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
340 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
344 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
346 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
347 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
348 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
351 trans.commit().get();
352 } catch (final InterruptedException | ExecutionException e) {
353 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
356 LOG.debug("Effective RIB created.");
358 this.localTablesKeys.forEach(this::startLocRib);
359 this.localTablesKeys.forEach(this::createLocRibWriter);
362 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
363 if (!this.isServiceInstantiated) {
364 LOG.trace("RIB {} already closed", this.ribId.getValue());
365 return CommitInfo.emptyFluentFuture();
367 LOG.info("Close RIB {}", this.ribId.getValue());
368 this.isServiceInstantiated = false;
371 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
372 this.txChainToLocRibWriter.clear();
374 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
375 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
376 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
377 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
379 public void onSuccess(final CommitInfo result) {
380 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
384 public void onFailure(final Throwable throwable) {
385 LOG.error("Failed to clean RIB {}",
386 RIBImpl.this.ribId.getValue(), throwable);
388 }, MoreExecutors.directExecutor());
389 this.domChain.close();