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).node(Rib.QNAME);
148 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
149 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
152 for (final BgpTableType t : this.localTables) {
153 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
154 this.localTablesKeys.add(key);
158 private synchronized void startLocRib(final TablesKey key) {
159 LOG.debug("Creating LocRib table for {}", key);
160 // create locRibWriter for each table
161 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
163 final RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
164 if (ribSupport != null) {
165 final MapEntryNode emptyTable = ribSupport.emptyTable();
166 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
167 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME)).node(emptyTable.getIdentifier());
169 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
172 } catch (final InterruptedException | ExecutionException e1) {
173 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
176 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
180 private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
181 R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
182 void createLocRibWriter(final TablesKey key) {
183 final RIBSupport<C, S, R, I> ribSupport = this.ribContextRegistry.getRIBSupport(key);
184 if (ribSupport == null) {
187 LOG.debug("Creating LocRIB writer for key {}", key);
188 final BindingTransactionChain txChain = createPeerChain(this);
189 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
190 if (pathSelectionStrategy == null) {
191 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
194 final LocRibWriter locRibWriter = LocRibWriter.create(
197 this.tableTypeRegistry.getAfiSafiType(key).get(),
199 getInstanceIdentifier(),
204 pathSelectionStrategy);
205 this.vpnTableRefresher.put(key, locRibWriter);
206 registerTotalPathCounter(key, locRibWriter);
207 registerTotalPrefixesCounter(key, locRibWriter);
208 this.txChainToLocRibWriter.put(txChain, locRibWriter);
212 public String toString() {
213 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
217 public synchronized void close() throws Exception {
218 if (this.registration != null) {
219 this.registration.close();
220 this.registration = null;
225 public AsNumber getLocalAs() {
230 public BgpId getBgpIdentifier() {
231 return this.bgpIdentifier;
236 public Set<? extends BgpTableType> getLocalTables() {
237 return this.localTables;
241 public BGPDispatcher getDispatcher() {
242 return this.dispatcher;
246 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
247 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
248 LOG.error("Broken chain in RIB {} transaction {}",
249 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
250 if (this.txChainToLocRibWriter.containsKey(chain)) {
251 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
252 final BindingTransactionChain newChain = createPeerChain(this);
253 startLocRib(locRibWriter.getTableKey());
254 locRibWriter.restart(newChain);
255 this.txChainToLocRibWriter.put(newChain, locRibWriter);
260 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
261 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
265 public Set<TablesKey> getLocalTablesKeys() {
266 return this.localTablesKeys;
270 public boolean supportsTable(final TablesKey tableKey) {
271 return this.localTablesKeys.contains(tableKey);
275 public BGPRibRoutingPolicy getRibPolicies() {
276 return this.ribPolicies;
280 public BGPPeerTracker getPeerTracker() {
281 return this.peerTracker;
285 public void refreshTable(final TablesKey tk, final PeerId peerId) {
286 final RibOutRefresh table = this.vpnTableRefresher.get(tk);
288 table.refreshTable(tk, peerId);
293 public DOMDataTreeChangeService getService() {
294 return (DOMDataTreeChangeService) this.domService;
298 public DataBroker getDataBroker() {
299 return this.dataBroker;
303 public YangInstanceIdentifier getYangRibId() {
304 return this.yangRibId;
308 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
309 return this.dataBroker.createTransactionChain(listener);
313 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
314 return this.domDataBroker.createTransactionChain(listener);
318 public RIBExtensionConsumerContext getRibExtensions() {
319 return this.extensions;
323 public RIBSupportContextRegistry getRibSupportContext() {
324 return this.ribContextRegistry;
328 public void onGlobalContextUpdated(final SchemaContext context) {
329 this.codecsRegistry.onSchemaContextUpdated(context);
333 public CodecsRegistry getCodecsRegistry() {
334 return this.codecsRegistry;
337 public synchronized void instantiateServiceInstance() {
338 this.isServiceInstantiated = true;
340 this.domChain = this.domDataBroker.createTransactionChain(this);
341 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
343 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
344 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
346 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
347 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
348 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
349 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
350 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
351 .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(), bgpRib);
359 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
362 trans.commit().get();
363 } catch (final InterruptedException | ExecutionException e) {
364 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
367 LOG.debug("Effective RIB created.");
369 this.localTablesKeys.forEach(this::startLocRib);
370 this.localTablesKeys.forEach(this::createLocRibWriter);
373 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
374 if (!this.isServiceInstantiated) {
375 LOG.trace("RIB {} already closed", this.ribId.getValue());
376 return CommitInfo.emptyFluentFuture();
378 LOG.info("Close RIB {}", this.ribId.getValue());
379 this.isServiceInstantiated = false;
382 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
383 this.txChainToLocRibWriter.clear();
385 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
386 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
387 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
388 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
390 public void onSuccess(final CommitInfo result) {
391 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
395 public void onFailure(final Throwable throwable) {
396 LOG.error("Failed to clean RIB {}",
397 RIBImpl.this.ribId.getValue(), throwable);
399 }, MoreExecutors.directExecutor());
400 this.domChain.close();