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 com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.BGPRIB_NID;
13 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.LOCRIB_NID;
14 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.PEER_NID;
15 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.RIB_NID;
16 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID;
18 import com.google.common.base.MoreObjects;
19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.util.concurrent.FluentFuture;
21 import com.google.common.util.concurrent.FutureCallback;
22 import com.google.common.util.concurrent.MoreExecutors;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
28 import java.util.concurrent.ExecutionException;
29 import java.util.stream.Collectors;
30 import org.checkerframework.checker.lock.qual.GuardedBy;
31 import org.opendaylight.mdsal.common.api.CommitInfo;
32 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
33 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
34 import org.opendaylight.mdsal.dom.api.DOMDataBroker.DataTreeChangeExtension;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
37 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
38 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
39 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
45 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRibStateImpl;
46 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
47 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
48 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
49 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.BgpId;
61 import org.opendaylight.yangtools.yang.binding.ChildOf;
62 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
63 import org.opendaylight.yangtools.yang.binding.DataObject;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.Empty;
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.NodeIdentifierWithPredicates;
70 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
72 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
73 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
77 // This class is thread-safe
78 public final class RIBImpl extends BGPRibStateImpl implements RIB {
79 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
80 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
82 private final BGPDispatcher dispatcher;
83 private final AsNumber localAs;
84 private final BgpId bgpIdentifier;
85 private final Set<BgpTableType> localTables;
86 private final Set<TablesKey> localTablesKeys;
87 private final DOMDataBroker domDataBroker;
88 private final RIBExtensionConsumerContext extensions;
89 private final YangInstanceIdentifier yangRibId;
90 private final RIBSupportContextRegistryImpl ribContextRegistry;
91 private final CodecsRegistry codecsRegistry;
92 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
93 private final DataTreeChangeExtension domService;
94 private final Map<DOMTransactionChain, LocRibWriter<?, ?>> txChainToLocRibWriter = new HashMap<>();
95 private final Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
96 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
97 private final RibId ribId;
98 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
99 private final BGPRibRoutingPolicy ribPolicies;
101 private DOMTransactionChain domChain;
103 private boolean isServiceInstantiated;
106 final BGPTableTypeRegistryConsumer tableTypeRegistry,
108 final AsNumber localAs,
109 final BgpId localBgpId,
110 final RIBExtensionConsumerContext extensions,
111 final BGPDispatcher dispatcher,
112 final CodecsRegistry codecsRegistry,
113 final DOMDataBroker domDataBroker,
114 final BGPRibRoutingPolicy ribPolicies,
115 final List<BgpTableType> localTables,
116 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
118 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
119 localBgpId, localAs);
120 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
121 this.localAs = requireNonNull(localAs);
122 bgpIdentifier = requireNonNull(localBgpId);
123 this.dispatcher = requireNonNull(dispatcher);
125 this.localTables = ImmutableSet.copyOf(localTables);
126 // FIXME: can this be immutable?
127 localTablesKeys = localTables.stream()
128 .map(t -> new TablesKey(t.getAfi(), t.getSafi()))
129 .collect(Collectors.toCollection(HashSet::new));
131 this.domDataBroker = requireNonNull(domDataBroker);
132 domService = domDataBroker.extension(DataTreeChangeExtension.class);
133 this.extensions = requireNonNull(extensions);
134 this.ribPolicies = requireNonNull(ribPolicies);
135 this.codecsRegistry = codecsRegistry;
136 ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecsRegistry);
137 yangRibId = YangInstanceIdentifier.builder().node(BGPRIB_NID).node(RIB_NID)
138 .nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
139 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
143 // FIXME: make this asynchronous?
144 private synchronized void startLocRib(final TablesKey key) {
145 LOG.debug("Creating LocRib table for {}", key);
146 // create locRibWriter for each table
147 final DOMDataTreeWriteTransaction tx = domChain.newWriteOnlyTransaction();
149 final RIBSupport<? extends Routes, ?> ribSupport = ribContextRegistry.getRIBSupport(key);
150 if (ribSupport != null) {
151 final MapEntryNode emptyTable = ribSupport.emptyTable();
152 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
153 .builder(yangRibId.node(LOCRIB_NID).node(TABLES_NID)).node(emptyTable.name());
155 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
158 } catch (final InterruptedException | ExecutionException e) {
159 LOG.error("Failed to initiate LocRIB for key {}", key, e);
162 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
166 private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
167 void createLocRibWriter(final TablesKey key) {
168 final RIBSupport<C, S> ribSupport = ribContextRegistry.getRIBSupport(key);
169 if (ribSupport == null) {
172 LOG.debug("Creating LocRIB writer for key {}", key);
173 final DOMTransactionChain txChain = createPeerDOMChain();
174 addCallback(txChain);
175 PathSelectionMode pathSelectionStrategy = bestPathSelectionStrategies.get(key);
176 if (pathSelectionStrategy == null) {
177 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
180 final LocRibWriter<C, S> locRibWriter = LocRibWriter.create(
182 verifyNotNull(tableTypeRegistry.getAfiSafiType(key)),
189 pathSelectionStrategy);
190 vpnTableRefresher.put(key, locRibWriter);
191 registerTotalPathCounter(key, locRibWriter);
192 registerTotalPrefixesCounter(key, locRibWriter);
193 txChainToLocRibWriter.put(txChain, locRibWriter);
197 public String toString() {
198 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
202 public AsNumber getLocalAs() {
207 public BgpId getBgpIdentifier() {
208 return bgpIdentifier;
212 public Set<? extends BgpTableType> getLocalTables() {
217 public BGPDispatcher getDispatcher() {
221 private void addCallback(final DOMTransactionChain txChain) {
222 txChain.addCallback(new FutureCallback<Empty>() {
224 public void onSuccess(final Empty result) {
225 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
229 public void onFailure(final Throwable cause) {
230 RIBImpl.this.onFailure(txChain, cause);
235 private synchronized void onFailure(final DOMTransactionChain chain, final Throwable cause) {
236 LOG.error("Broken chain in RIB {}", getInstanceIdentifier(), cause);
237 final LocRibWriter<?, ?> locRibWriter = txChainToLocRibWriter.remove(chain);
238 if (locRibWriter != null) {
239 final DOMTransactionChain newChain = createPeerDOMChain();
240 addCallback(newChain);
241 startLocRib(locRibWriter.getTableKey());
242 locRibWriter.restart(newChain);
243 txChainToLocRibWriter.put(newChain, locRibWriter);
248 public Set<TablesKey> getLocalTablesKeys() {
249 return localTablesKeys;
253 public boolean supportsTable(final TablesKey tableKey) {
254 return localTablesKeys.contains(tableKey);
258 public BGPRibRoutingPolicy getRibPolicies() {
263 public BGPPeerTracker getPeerTracker() {
268 public void refreshTable(final TablesKey tk, final PeerId peerId) {
269 final RibOutRefresh table = vpnTableRefresher.get(tk);
271 table.refreshTable(tk, peerId);
276 public DataTreeChangeExtension getService() {
281 public YangInstanceIdentifier getYangRibId() {
286 public DOMTransactionChain createPeerDOMChain() {
287 return domDataBroker.createMergingTransactionChain();
291 public RIBExtensionConsumerContext getRibExtensions() {
296 public RIBSupportContextRegistry getRibSupportContext() {
297 return ribContextRegistry;
301 public CodecsRegistry getCodecsRegistry() {
302 return codecsRegistry;
305 public synchronized void instantiateServiceInstance() {
306 LOG.debug("Instantiating RIB table {} at {}", ribId, yangRibId);
308 isServiceInstantiated = true;
310 domChain = domDataBroker.createMergingTransactionChain();
311 addCallback(domChain);
313 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(BGPRIB_NID)
314 .addChild(ImmutableNodes.mapNodeBuilder(RIB_NID).build()).build();
316 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
317 NodeIdentifierWithPredicates.of(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
318 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
319 .addChild(ImmutableNodes.mapNodeBuilder(PEER_NID).build())
320 .addChild(Builders.containerBuilder().withNodeIdentifier(LOCRIB_NID)
321 .addChild(ImmutableNodes.mapNodeBuilder(TABLES_NID).build())
324 final DOMDataTreeWriteTransaction trans = domChain.newWriteOnlyTransaction();
326 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
327 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.of(BGPRIB_NID), bgpRib);
328 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibId, ribInstance);
331 trans.commit().get();
332 } catch (final InterruptedException | ExecutionException e) {
333 LOG.error("Failed to initiate RIB {}", yangRibId, e);
336 LOG.debug("Effective RIB created.");
338 localTablesKeys.forEach(this::startLocRib);
339 localTablesKeys.forEach(this::createLocRibWriter);
342 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
343 if (!isServiceInstantiated) {
344 LOG.trace("RIB {} already closed", ribId.getValue());
345 return CommitInfo.emptyFluentFuture();
347 LOG.info("Close RIB {}", ribId.getValue());
348 isServiceInstantiated = false;
351 txChainToLocRibWriter.values().forEach(LocRibWriter::close);
352 txChainToLocRibWriter.clear();
354 final DOMDataTreeWriteTransaction t = domChain.newWriteOnlyTransaction();
355 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
356 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
357 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
359 public void onSuccess(final CommitInfo result) {
360 LOG.info("RIB cleaned {}", ribId.getValue());
364 public void onFailure(final Throwable throwable) {
365 LOG.error("Failed to clean RIB {}",
366 ribId.getValue(), throwable);
368 }, MoreExecutors.directExecutor());