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.spi.node.ImmutableNodes;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
76 // This class is thread-safe
77 public final class RIBImpl extends BGPRibStateImpl implements RIB {
78 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
79 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
81 private final BGPDispatcher dispatcher;
82 private final AsNumber localAs;
83 private final BgpId bgpIdentifier;
84 private final Set<BgpTableType> localTables;
85 private final Set<TablesKey> localTablesKeys;
86 private final DOMDataBroker domDataBroker;
87 private final RIBExtensionConsumerContext extensions;
88 private final YangInstanceIdentifier yangRibId;
89 private final RIBSupportContextRegistryImpl ribContextRegistry;
90 private final CodecsRegistry codecsRegistry;
91 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
92 private final DataTreeChangeExtension domService;
93 private final Map<DOMTransactionChain, LocRibWriter<?, ?>> txChainToLocRibWriter = new HashMap<>();
94 private final Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
95 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
96 private final RibId ribId;
97 private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
98 private final BGPRibRoutingPolicy ribPolicies;
100 private DOMTransactionChain domChain;
102 private boolean isServiceInstantiated;
105 final BGPTableTypeRegistryConsumer tableTypeRegistry,
107 final AsNumber localAs,
108 final BgpId localBgpId,
109 final RIBExtensionConsumerContext extensions,
110 final BGPDispatcher dispatcher,
111 final CodecsRegistry codecsRegistry,
112 final DOMDataBroker domDataBroker,
113 final BGPRibRoutingPolicy ribPolicies,
114 final List<BgpTableType> localTables,
115 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
117 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
118 localBgpId, localAs);
119 this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
120 this.localAs = requireNonNull(localAs);
121 bgpIdentifier = requireNonNull(localBgpId);
122 this.dispatcher = requireNonNull(dispatcher);
124 this.localTables = ImmutableSet.copyOf(localTables);
125 // FIXME: can this be immutable?
126 localTablesKeys = localTables.stream()
127 .map(t -> new TablesKey(t.getAfi(), t.getSafi()))
128 .collect(Collectors.toCollection(HashSet::new));
130 this.domDataBroker = requireNonNull(domDataBroker);
131 domService = domDataBroker.extension(DataTreeChangeExtension.class);
132 this.extensions = requireNonNull(extensions);
133 this.ribPolicies = requireNonNull(ribPolicies);
134 this.codecsRegistry = codecsRegistry;
135 ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecsRegistry);
136 yangRibId = YangInstanceIdentifier.builder().node(BGPRIB_NID).node(RIB_NID)
137 .nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
138 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
142 // FIXME: make this asynchronous?
143 private synchronized void startLocRib(final TablesKey key) {
144 LOG.debug("Creating LocRib table for {}", key);
145 // create locRibWriter for each table
146 final DOMDataTreeWriteTransaction tx = domChain.newWriteOnlyTransaction();
148 final RIBSupport<? extends Routes, ?> ribSupport = ribContextRegistry.getRIBSupport(key);
149 if (ribSupport != null) {
150 final MapEntryNode emptyTable = ribSupport.emptyTable();
151 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
152 .builder(yangRibId.node(LOCRIB_NID).node(TABLES_NID)).node(emptyTable.name());
154 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
157 } catch (final InterruptedException | ExecutionException e) {
158 LOG.error("Failed to initiate LocRIB for key {}", key, e);
161 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
165 private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
166 void createLocRibWriter(final TablesKey key) {
167 final RIBSupport<C, S> ribSupport = ribContextRegistry.getRIBSupport(key);
168 if (ribSupport == null) {
171 LOG.debug("Creating LocRIB writer for key {}", key);
172 final DOMTransactionChain txChain = createPeerDOMChain();
173 addCallback(txChain);
174 PathSelectionMode pathSelectionStrategy = bestPathSelectionStrategies.get(key);
175 if (pathSelectionStrategy == null) {
176 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
179 final LocRibWriter<C, S> locRibWriter = LocRibWriter.create(
181 verifyNotNull(tableTypeRegistry.getAfiSafiType(key)),
188 pathSelectionStrategy);
189 vpnTableRefresher.put(key, locRibWriter);
190 registerTotalPathCounter(key, locRibWriter);
191 registerTotalPrefixesCounter(key, locRibWriter);
192 txChainToLocRibWriter.put(txChain, locRibWriter);
196 public String toString() {
197 return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
201 public AsNumber getLocalAs() {
206 public BgpId getBgpIdentifier() {
207 return bgpIdentifier;
211 public Set<? extends BgpTableType> getLocalTables() {
216 public BGPDispatcher getDispatcher() {
220 private void addCallback(final DOMTransactionChain txChain) {
221 txChain.addCallback(new FutureCallback<Empty>() {
223 public void onSuccess(final Empty result) {
224 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
228 public void onFailure(final Throwable cause) {
229 RIBImpl.this.onFailure(txChain, cause);
234 private synchronized void onFailure(final DOMTransactionChain chain, final Throwable cause) {
235 LOG.error("Broken chain in RIB {}", getInstanceIdentifier(), cause);
236 final LocRibWriter<?, ?> locRibWriter = txChainToLocRibWriter.remove(chain);
237 if (locRibWriter != null) {
238 final DOMTransactionChain newChain = createPeerDOMChain();
239 addCallback(newChain);
240 startLocRib(locRibWriter.getTableKey());
241 locRibWriter.restart(newChain);
242 txChainToLocRibWriter.put(newChain, locRibWriter);
247 public Set<TablesKey> getLocalTablesKeys() {
248 return localTablesKeys;
252 public boolean supportsTable(final TablesKey tableKey) {
253 return localTablesKeys.contains(tableKey);
257 public BGPRibRoutingPolicy getRibPolicies() {
262 public BGPPeerTracker getPeerTracker() {
267 public void refreshTable(final TablesKey tk, final PeerId peerId) {
268 final RibOutRefresh table = vpnTableRefresher.get(tk);
270 table.refreshTable(tk, peerId);
275 public DataTreeChangeExtension getService() {
280 public YangInstanceIdentifier getYangRibId() {
285 public DOMTransactionChain createPeerDOMChain() {
286 return domDataBroker.createMergingTransactionChain();
290 public RIBExtensionConsumerContext getRibExtensions() {
295 public RIBSupportContextRegistry getRibSupportContext() {
296 return ribContextRegistry;
300 public CodecsRegistry getCodecsRegistry() {
301 return codecsRegistry;
304 public synchronized void instantiateServiceInstance() {
305 LOG.debug("Instantiating RIB table {} at {}", ribId, yangRibId);
307 isServiceInstantiated = true;
309 domChain = domDataBroker.createMergingTransactionChain();
310 addCallback(domChain);
312 final ContainerNode bgpRib = ImmutableNodes.newContainerBuilder().withNodeIdentifier(BGPRIB_NID)
313 .addChild(ImmutableNodes.newSystemMapBuilder().withNodeIdentifier(RIB_NID).build()).build();
315 final MapEntryNode ribInstance = ImmutableNodes.newMapEntryBuilder()
316 .withNodeIdentifier(NodeIdentifierWithPredicates.of(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
317 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
318 .addChild(ImmutableNodes.newSystemMapBuilder().withNodeIdentifier(PEER_NID).build())
319 .addChild(ImmutableNodes.newContainerBuilder().withNodeIdentifier(LOCRIB_NID)
320 .addChild(ImmutableNodes.newSystemMapBuilder().withNodeIdentifier(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());