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 com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Map.Entry;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.ThreadSafe;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
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.protocol.bgp.mode.api.PathSelectionMode;
39 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
40 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
41 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
42 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
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.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
48 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
49 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
50 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
66 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
67 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.common.QName;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
77 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
78 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
79 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
81 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
87 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
89 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
91 public static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes.QNAME);
93 private final ReconnectStrategyFactory tcpStrategyFactory;
94 private final ReconnectStrategyFactory sessionStrategyFactory;
96 private final BGPDispatcher dispatcher;
97 private final DOMTransactionChain domChain;
98 private final AsNumber localAs;
99 private final Ipv4Address bgpIdentifier;
100 private final Set<BgpTableType> localTables;
101 private final Set<TablesKey> localTablesKeys;
102 private final DataBroker dataBroker;
103 private final DOMDataBroker domDataBroker;
104 private final RIBExtensionConsumerContext extensions;
105 private final YangInstanceIdentifier yangRibId;
106 private final RIBSupportContextRegistryImpl ribContextRegistry;
107 private final CodecsRegistryImpl codecsRegistry;
108 private final EffectiveRibInWriter efWriter;
109 private final DOMDataBrokerExtension service;
110 private final List<LocRibWriter> locRibs = new ArrayList<>();
111 private final BGPConfigModuleTracker configModuleTracker;
112 private final BGPOpenConfigProvider openConfigProvider;
113 private final CacheDisconnectedPeers cacheDisconnectedPeers;
114 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
116 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
117 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
118 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
119 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
120 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
121 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
122 this.domChain = domDataBroker.createTransactionChain(this);
123 this.localAs = Preconditions.checkNotNull(localAs);
124 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
125 this.dispatcher = Preconditions.checkNotNull(dispatcher);
126 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
127 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
128 this.localTables = ImmutableSet.copyOf(localTables);
129 this.localTablesKeys = new HashSet<>();
130 this.dataBroker = dps;
131 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
132 this.extensions = Preconditions.checkNotNull(extensions);
133 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
134 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
135 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
136 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
137 this.configModuleTracker = moduleTracker;
138 this.openConfigProvider = openConfigProvider;
139 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
140 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
142 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
144 final ContainerNode bgpRib = Builders.containerBuilder()
145 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
146 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
148 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
149 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
150 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
151 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
152 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
153 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
157 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
159 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
160 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
161 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
164 trans.submit().checkedGet();
165 } catch (final TransactionCommitFailedException e) {
166 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
168 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
169 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
171 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
172 this.service = domDatatreeChangeService;
173 this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
174 LOG.debug("Effective RIB created.");
176 for (final BgpTableType t : this.localTables) {
177 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
178 this.localTablesKeys.add(key);
179 startLocRib(key, pd);
182 if (this.configModuleTracker != null) {
183 this.configModuleTracker.onInstanceCreate();
187 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
188 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
189 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
190 final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
191 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, tcpStrategyFactory, codecFactory, sessionStrategyFactory,
192 dps, domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
195 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
196 LOG.debug("Creating LocRib table for {}", key);
197 // create locRibWriter for each table
198 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
200 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
201 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
202 table.withChild(EMPTY_TABLE_ATTRIBUTES);
204 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
205 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
206 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
207 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
208 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
211 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
212 table.withChild(routes);
214 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
216 tx.submit().checkedGet();
217 } catch (final TransactionCommitFailedException e1) {
218 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
221 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
222 if (pathSelectionStrategy == null) {
223 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
225 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
226 this.cacheDisconnectedPeers, pathSelectionStrategy));
230 public String toString() {
231 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
234 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
235 return toStringHelper;
239 public synchronized void close() throws InterruptedException, ExecutionException {
240 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
241 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
243 this.domChain.close();
244 this.efWriter.close();
245 for (final LocRibWriter locRib : this.locRibs) {
248 } catch (final Exception e) {
249 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
252 if (this.configModuleTracker != null) {
253 this.configModuleTracker.onInstanceClose();
258 public AsNumber getLocalAs() {
263 public Ipv4Address getBgpIdentifier() {
264 return this.bgpIdentifier;
268 public Set<? extends BgpTableType> getLocalTables() {
269 return this.localTables;
273 public ReconnectStrategyFactory getTcpStrategyFactory() {
274 return this.tcpStrategyFactory;
278 public ReconnectStrategyFactory getSessionStrategyFactory() {
279 return this.sessionStrategyFactory;
283 public BGPDispatcher getDispatcher() {
284 return this.dispatcher;
288 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
289 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
293 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
294 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
298 public long getRoutesCount(final TablesKey key) {
299 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
300 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
301 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
302 if (tableMaybe.isPresent()) {
303 final Tables table = tableMaybe.get();
304 return countIpRoutes(table.getRoutes());
306 } catch (final ReadFailedException e) {
307 LOG.debug("Failed to read tables", e);
312 private int countIpRoutes(final Routes routes) {
313 if (routes instanceof Ipv4RoutesCase) {
314 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
315 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
316 return routesCase.getIpv4Routes().getIpv4Route().size();
318 } else if (routes instanceof Ipv6RoutesCase) {
319 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
320 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
321 return routesCase.getIpv6Routes().getIpv6Route().size();
327 public Set<TablesKey> getLocalTablesKeys() {
328 return this.localTablesKeys;
331 public DOMDataTreeChangeService getService() {
332 return (DOMDataTreeChangeService) this.service;
336 public YangInstanceIdentifier getYangRibId() {
337 return this.yangRibId;
341 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
342 return this.domDataBroker.createTransactionChain(listener);
346 public RIBExtensionConsumerContext getRibExtensions() {
347 return this.extensions;
351 public RIBSupportContextRegistry getRibSupportContext() {
352 return this.ribContextRegistry;
356 public void onGlobalContextUpdated(final SchemaContext context) {
357 this.codecsRegistry.onSchemaContextUpdated(context);
361 public CodecsRegistry getCodecsRegistry() {
362 return this.codecsRegistry;
366 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
367 return Optional.fromNullable(this.openConfigProvider);
371 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
372 return this.cacheDisconnectedPeers;