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;
11 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.BGPRIB;
12 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.LOCRIB;
13 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.RIB;
14 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES;
16 import com.google.common.base.MoreObjects;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.util.concurrent.FluentFuture;
19 import com.google.common.util.concurrent.FutureCallback;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import javax.annotation.Nonnull;
28 import javax.annotation.concurrent.GuardedBy;
29 import javax.annotation.concurrent.ThreadSafe;
30 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
35 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
40 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
41 import org.opendaylight.mdsal.common.api.CommitInfo;
42 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
43 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
44 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
45 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
51 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
52 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
53 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
54 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
55 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpId;
69 import org.opendaylight.yangtools.yang.binding.ChildOf;
70 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
71 import org.opendaylight.yangtools.yang.binding.DataObject;
72 import org.opendaylight.yangtools.yang.binding.Identifiable;
73 import org.opendaylight.yangtools.yang.binding.Identifier;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.QName;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
77 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
78 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
79 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
81 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
82 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
83 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
84 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
90 SchemaContextListener, AutoCloseable {
91 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
92 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
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 DataBroker dataBroker;
101 private final RIBExtensionConsumerContext extensions;
102 private final YangInstanceIdentifier yangRibId;
103 private final RIBSupportContextRegistryImpl ribContextRegistry;
104 private final CodecsRegistryImpl codecsRegistry;
105 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
106 private final DOMDataBrokerExtension domService;
107 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
108 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109 private final RibId ribId;
110 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
111 private final BGPRibRoutingPolicy ribPolicies;
113 private ClusterSingletonServiceRegistration registration;
115 private DOMTransactionChain domChain;
117 private boolean isServiceInstantiated;
118 private final Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
121 final BGPTableTypeRegistryConsumer tableTypeRegistry,
123 final AsNumber localAs,
124 final BgpId localBgpId,
125 final RIBExtensionConsumerContext extensions,
126 final BGPDispatcher dispatcher,
127 final CodecsRegistryImpl codecsRegistry,
128 final DOMDataBroker domDataBroker,
129 final DataBroker dataBroker,
130 final BGPRibRoutingPolicy ribPolicies,
131 final List<BgpTableType> localTables,
132 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
134 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
135 localBgpId, localAs);
136 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
137 this.localAs = requireNonNull(localAs);
138 this.bgpIdentifier = requireNonNull(localBgpId);
139 this.dispatcher = requireNonNull(dispatcher);
140 this.localTables = ImmutableSet.copyOf(localTables);
141 this.localTablesKeys = new HashSet<>();
142 this.domDataBroker = requireNonNull(domDataBroker);
143 this.dataBroker = requireNonNull(dataBroker);
144 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
145 this.extensions = requireNonNull(extensions);
146 this.ribPolicies = requireNonNull(ribPolicies);
147 this.codecsRegistry = codecsRegistry;
148 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
149 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BGPRIB).node(RIB);
150 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
151 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
154 for (final BgpTableType t : this.localTables) {
155 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
156 this.localTablesKeys.add(key);
160 private synchronized 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 RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
166 if (ribSupport != null) {
167 final MapEntryNode emptyTable = ribSupport.emptyTable();
168 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
169 .builder(this.yangRibId.node(LOCRIB).node(TABLES)).node(emptyTable.getIdentifier());
171 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
174 } catch (final InterruptedException | ExecutionException e1) {
175 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
178 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
182 private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
183 R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
184 void createLocRibWriter(final TablesKey key) {
185 final RIBSupport<C, S, R, I> ribSupport = this.ribContextRegistry.getRIBSupport(key);
186 if (ribSupport == null) {
189 LOG.debug("Creating LocRIB writer for key {}", key);
190 final BindingTransactionChain txChain = createPeerChain(this);
191 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
192 if (pathSelectionStrategy == null) {
193 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
196 final LocRibWriter<C, S, R, I> 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(BGPRIB)
345 .addChild(ImmutableNodes.mapNodeBuilder(RIB).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(LOCRIB)
352 .addChild(ImmutableNodes.mapNodeBuilder(TABLES).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.create(BGPRIB), 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();