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.base.MoreObjects.ToStringHelper;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.util.concurrent.FluentFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import java.util.concurrent.ExecutionException;
25 import javax.annotation.Nonnull;
26 import javax.annotation.concurrent.GuardedBy;
27 import javax.annotation.concurrent.ThreadSafe;
28 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
38 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
39 import org.opendaylight.mdsal.common.api.CommitInfo;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
41 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
42 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
48 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
49 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
51 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
52 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
53 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
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.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.ChoiceNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
74 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
75 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
76 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
78 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
84 SchemaContextListener, AutoCloseable {
85 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
86 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
87 private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang
88 .gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Attributes.QNAME);
90 private final BGPDispatcher dispatcher;
91 private final AsNumber localAs;
92 private final BgpId bgpIdentifier;
93 private final Set<BgpTableType> localTables;
94 private final Set<TablesKey> localTablesKeys;
95 private final DOMDataBroker domDataBroker;
96 private final DataBroker dataBroker;
97 private final RIBExtensionConsumerContext extensions;
98 private final YangInstanceIdentifier yangRibId;
99 private final RIBSupportContextRegistryImpl ribContextRegistry;
100 private final CodecsRegistryImpl codecsRegistry;
102 private ClusterSingletonServiceRegistration registration;
103 private final DOMDataBrokerExtension domService;
104 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
105 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
106 private final RibId ribId;
107 private final BGPPeerTracker peerTracker;
108 private final BGPRibRoutingPolicy ribPolicies;
111 private DOMTransactionChain domChain;
113 private boolean isServiceInstantiated;
115 public RIBImpl(final RibId ribId,
116 final AsNumber localAs,
117 final BgpId localBgpId,
118 final RIBExtensionConsumerContext extensions,
119 final BGPDispatcher dispatcher,
120 final CodecsRegistryImpl codecsRegistry,
121 final DOMDataBroker domDataBroker,
122 final DataBroker dataBroker,
123 final BGPRibRoutingPolicy ribPolicies,
124 final BGPPeerTracker bgpPeerTracker,
125 final List<BgpTableType> localTables,
126 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
128 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
129 localBgpId, localAs);
130 this.localAs = requireNonNull(localAs);
131 this.bgpIdentifier = requireNonNull(localBgpId);
132 this.dispatcher = requireNonNull(dispatcher);
133 this.localTables = ImmutableSet.copyOf(localTables);
134 this.localTablesKeys = new HashSet<>();
135 this.domDataBroker = requireNonNull(domDataBroker);
136 this.dataBroker = requireNonNull(dataBroker);
137 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
138 this.extensions = requireNonNull(extensions);
139 this.ribPolicies = requireNonNull(ribPolicies);
140 this.peerTracker = requireNonNull(bgpPeerTracker);
141 this.codecsRegistry = codecsRegistry;
142 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
143 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
144 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
145 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
148 for (final BgpTableType t : this.localTables) {
149 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
150 this.localTablesKeys.add(key);
154 private synchronized void startLocRib(final TablesKey key) {
155 LOG.debug("Creating LocRib table for {}", key);
156 // create locRibWriter for each table
157 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
159 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
160 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
161 table.withChild(EMPTY_TABLE_ATTRIBUTES);
163 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
164 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
165 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
166 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
167 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
168 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
171 final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
172 if (supportContext != null) {
173 final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
174 table.withChild(routes);
176 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
179 } catch (final InterruptedException | ExecutionException e1) {
180 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
183 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
187 private synchronized void createLocRibWriter(final TablesKey key) {
188 final RIBSupport ribSupport = this.ribContextRegistry.getRIBSupport(key);
189 if (ribSupport == null) {
192 LOG.debug("Creating LocRIB writer for key {}", key);
193 final BindingTransactionChain txChain = createPeerChain(this);
194 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
195 if (pathSelectionStrategy == null) {
196 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy(this.peerTracker);
199 final LocRibWriter locRibWriter = LocRibWriter.create(
203 getInstanceIdentifier(),
208 pathSelectionStrategy);
209 registerTotalPathCounter(key, locRibWriter);
210 registerTotalPrefixesCounter(key, locRibWriter);
211 this.txChainToLocRibWriter.put(txChain, locRibWriter);
215 public String toString() {
216 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
219 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
220 return toStringHelper;
224 public synchronized void close() throws Exception {
225 if (this.registration != null) {
226 this.registration.close();
227 this.registration = null;
232 public AsNumber getLocalAs() {
237 public BgpId getBgpIdentifier() {
238 return this.bgpIdentifier;
243 public Set<? extends BgpTableType> getLocalTables() {
244 return this.localTables;
248 public BGPDispatcher getDispatcher() {
249 return this.dispatcher;
253 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
254 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
255 LOG.error("Broken chain in RIB {} transaction {}",
256 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
257 if (this.txChainToLocRibWriter.containsKey(chain)) {
258 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
259 final BindingTransactionChain newChain = createPeerChain(this);
260 startLocRib(locRibWriter.getTableKey());
261 locRibWriter.restart(newChain);
262 this.txChainToLocRibWriter.put(newChain, locRibWriter);
267 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
268 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
272 public Set<TablesKey> getLocalTablesKeys() {
273 return this.localTablesKeys;
277 public boolean supportsTable(final TablesKey tableKey) {
278 return this.localTablesKeys.contains(tableKey);
282 public BGPRibRoutingPolicy getRibPolicies() {
283 return this.ribPolicies;
287 public BGPPeerTracker getPeerTracker() {
288 return this.peerTracker;
292 public DOMDataTreeChangeService getService() {
293 return (DOMDataTreeChangeService) this.domService;
297 public DataBroker getDataBroker() {
298 return this.dataBroker;
302 public YangInstanceIdentifier getYangRibId() {
303 return this.yangRibId;
307 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
308 return this.dataBroker.createTransactionChain(listener);
312 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
313 return this.domDataBroker.createTransactionChain(listener);
317 public RIBExtensionConsumerContext getRibExtensions() {
318 return this.extensions;
322 public RIBSupportContextRegistry getRibSupportContext() {
323 return this.ribContextRegistry;
327 public void onGlobalContextUpdated(final SchemaContext context) {
328 this.codecsRegistry.onSchemaContextUpdated(context);
332 public CodecsRegistry getCodecsRegistry() {
333 return this.codecsRegistry;
336 public synchronized void instantiateServiceInstance() {
337 this.isServiceInstantiated = true;
339 this.domChain = this.domDataBroker.createTransactionChain(this);
340 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
342 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
343 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
345 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
346 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
347 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
348 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
349 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
350 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
354 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
356 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
357 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
358 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
361 trans.commit().get();
362 } catch (final InterruptedException | ExecutionException e) {
363 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
366 LOG.debug("Effective RIB created.");
368 this.localTablesKeys.forEach(this::startLocRib);
369 this.localTablesKeys.forEach(this::createLocRibWriter);
372 public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
373 if (!this.isServiceInstantiated) {
374 LOG.trace("RIB {} already closed", this.ribId.getValue());
375 return CommitInfo.emptyFluentFuture();
377 LOG.info("Close RIB {}", this.ribId.getValue());
378 this.isServiceInstantiated = false;
381 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
382 this.txChainToLocRibWriter.clear();
384 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
385 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
386 final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
387 cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
389 public void onSuccess(final CommitInfo result) {
390 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
394 public void onFailure(final Throwable throwable) {
395 LOG.error("Failed to clean RIB {}",
396 RIBImpl.this.ribId.getValue(), throwable);
398 }, MoreExecutors.directExecutor());
399 this.domChain.close();