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.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
21 import java.util.Map.Entry;
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.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
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.rib.impl.spi.BGPDispatcher;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
46 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
47 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
48 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
49 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
50 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
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.rev171207.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.RibId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.opendaylight.yangtools.yang.common.QName;
65 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
66 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
69 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
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.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
82 SchemaContextListener, AutoCloseable {
83 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
84 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
85 private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang
86 .gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Attributes.QNAME);
88 private final BGPDispatcher dispatcher;
89 private final AsNumber localAs;
90 private final BgpId bgpIdentifier;
91 private final Set<BgpTableType> localTables;
92 private final Set<TablesKey> localTablesKeys;
93 private final DOMDataBroker domDataBroker;
94 private final DataBroker dataBroker;
95 private final RIBExtensionConsumerContext extensions;
96 private final YangInstanceIdentifier yangRibId;
97 private final RIBSupportContextRegistryImpl ribContextRegistry;
98 private final CodecsRegistryImpl codecsRegistry;
100 private ClusterSingletonServiceRegistration registration;
101 private final DOMDataBrokerExtension domService;
102 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
103 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
104 private final RibId ribId;
105 private final BGPPeerTracker peerTracker;
106 private final BGPRibRoutingPolicy ribPolicies;
109 private DOMTransactionChain domChain;
111 private boolean isServiceInstantiated;
113 public RIBImpl(final RibId ribId,
114 final AsNumber localAs,
115 final BgpId localBgpId,
116 final RIBExtensionConsumerContext extensions,
117 final BGPDispatcher dispatcher,
118 final CodecsRegistryImpl codecsRegistry,
119 final DOMDataBroker domDataBroker,
120 final DataBroker dataBroker,
121 final BGPRibRoutingPolicy ribPolicies,
122 final BGPPeerTracker bgpPeerTracker,
123 final List<BgpTableType> localTables,
124 final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
126 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
127 localBgpId, localAs);
128 this.localAs = requireNonNull(localAs);
129 this.bgpIdentifier = requireNonNull(localBgpId);
130 this.dispatcher = requireNonNull(dispatcher);
131 this.localTables = ImmutableSet.copyOf(localTables);
132 this.localTablesKeys = new HashSet<>();
133 this.domDataBroker = requireNonNull(domDataBroker);
134 this.dataBroker = requireNonNull(dataBroker);
135 this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
136 this.extensions = requireNonNull(extensions);
137 this.ribPolicies = requireNonNull(ribPolicies);
138 this.peerTracker = requireNonNull(bgpPeerTracker);
139 this.codecsRegistry = codecsRegistry;
140 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
141 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
142 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
143 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
146 for (final BgpTableType t : this.localTables) {
147 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
148 this.localTablesKeys.add(key);
152 private synchronized void startLocRib(final TablesKey key) {
153 LOG.debug("Creating LocRib table for {}", key);
154 // create locRibWriter for each table
155 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
157 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
158 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
159 table.withChild(EMPTY_TABLE_ATTRIBUTES);
161 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
162 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
163 .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
164 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
165 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
166 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
169 final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
170 if (supportContext != null) {
171 final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
172 table.withChild(routes);
174 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
176 tx.submit().checkedGet();
177 } catch (final TransactionCommitFailedException e1) {
178 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
181 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
185 private synchronized void createLocRibWriter(final TablesKey key) {
186 final RIBSupport ribSupport = this.ribContextRegistry.getRIBSupport(key);
187 if (ribSupport == null) {
190 LOG.debug("Creating LocRIB writer for key {}", key);
191 final BindingTransactionChain txChain = createPeerChain(this);
192 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
193 if (pathSelectionStrategy == null) {
194 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy(this.peerTracker);
197 final LocRibWriter locRibWriter = LocRibWriter.create(
201 getInstanceIdentifier(),
206 pathSelectionStrategy);
207 registerTotalPathCounter(key, locRibWriter);
208 registerTotalPrefixesCounter(key, locRibWriter);
209 this.txChainToLocRibWriter.put(txChain, locRibWriter);
213 public String toString() {
214 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
217 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
218 return toStringHelper;
222 public synchronized void close() throws Exception {
223 if (this.registration != null) {
224 this.registration.close();
225 this.registration = null;
230 public AsNumber getLocalAs() {
235 public BgpId getBgpIdentifier() {
236 return this.bgpIdentifier;
241 public Set<? extends BgpTableType> getLocalTables() {
242 return this.localTables;
246 public BGPDispatcher getDispatcher() {
247 return this.dispatcher;
251 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain,
252 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
253 LOG.error("Broken chain in RIB {} transaction {}",
254 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
255 if (this.txChainToLocRibWriter.containsKey(chain)) {
256 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
257 final BindingTransactionChain newChain = createPeerChain(this);
258 startLocRib(locRibWriter.getTableKey());
259 locRibWriter.restart(newChain);
260 this.txChainToLocRibWriter.put(newChain, locRibWriter);
265 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
266 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
270 public Set<TablesKey> getLocalTablesKeys() {
271 return this.localTablesKeys;
275 public boolean supportsTable(final TablesKey tableKey) {
276 return this.localTablesKeys.contains(tableKey);
280 public BGPRibRoutingPolicy getRibPolicies() {
281 return this.ribPolicies;
285 public BGPPeerTracker getPeerTracker() {
286 return this.peerTracker;
290 public DOMDataTreeChangeService getService() {
291 return (DOMDataTreeChangeService) this.domService;
295 public DataBroker getDataBroker() {
296 return this.dataBroker;
300 public YangInstanceIdentifier getYangRibId() {
301 return this.yangRibId;
305 public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
306 return this.dataBroker.createTransactionChain(listener);
310 public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
311 return this.domDataBroker.createTransactionChain(listener);
315 public RIBExtensionConsumerContext getRibExtensions() {
316 return this.extensions;
320 public RIBSupportContextRegistry getRibSupportContext() {
321 return this.ribContextRegistry;
325 public void onGlobalContextUpdated(final SchemaContext context) {
326 this.codecsRegistry.onSchemaContextUpdated(context);
330 public CodecsRegistry getCodecsRegistry() {
331 return this.codecsRegistry;
334 public synchronized void instantiateServiceInstance() {
335 this.isServiceInstantiated = true;
337 this.domChain = this.domDataBroker.createTransactionChain(this);
338 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
340 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
341 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
343 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
344 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
345 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
346 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
347 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
348 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
352 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
354 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
355 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
356 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
359 trans.submit().checkedGet();
360 } catch (final TransactionCommitFailedException e) {
361 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
364 LOG.debug("Effective RIB created.");
366 this.localTablesKeys.forEach(this::startLocRib);
367 this.localTablesKeys.forEach(this::createLocRibWriter);
370 public synchronized ListenableFuture<Void> closeServiceInstance() {
371 if (!this.isServiceInstantiated) {
372 LOG.trace("RIB {} already closed", this.ribId.getValue());
373 return Futures.immediateFuture(null);
375 LOG.info("Close RIB {}", this.ribId.getValue());
376 this.isServiceInstantiated = false;
379 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
380 this.txChainToLocRibWriter.clear();
382 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
383 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
384 final ListenableFuture<Void> cleanFuture = t.submit();
386 this.domChain.close();