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;
19 import java.util.Map.Entry;
21 import java.util.concurrent.ExecutionException;
22 import javax.annotation.concurrent.ThreadSafe;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
36 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
37 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
38 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
43 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
44 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
45 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
46 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
62 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
63 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.QName;
66 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
70 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
72 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
73 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
74 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
75 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
77 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
82 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
83 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
85 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
87 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);
89 private final ReconnectStrategyFactory tcpStrategyFactory;
90 private final ReconnectStrategyFactory sessionStrategyFactory;
92 private final BGPDispatcher dispatcher;
93 private final DOMTransactionChain domChain;
94 private final AsNumber localAs;
95 private final Ipv4Address bgpIdentifier;
96 private final Set<BgpTableType> localTables;
97 private final Set<TablesKey> localTablesKeys;
98 private final DataBroker dataBroker;
99 private final DOMDataBroker domDataBroker;
100 private final RIBExtensionConsumerContext extensions;
101 private final YangInstanceIdentifier yangRibId;
102 private final RIBSupportContextRegistryImpl ribContextRegistry;
103 private final CodecsRegistryImpl codecsRegistry;
104 private final EffectiveRibInWriter efWriter;
105 private final DOMDataBrokerExtension service;
106 private final List<LocRibWriter> locRibs = new ArrayList<>();
107 private final BGPConfigModuleTracker configModuleTracker;
108 private final BGPOpenConfigProvider openConfigProvider;
109 private final CacheDisconnectedPeers cacheDisconnectedPeers;
111 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
112 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
113 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
114 final GeneratedClassLoadingStrategy classStrategy, final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
115 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
116 this.domChain = domDataBroker.createTransactionChain(this);
117 this.localAs = Preconditions.checkNotNull(localAs);
118 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
119 this.dispatcher = Preconditions.checkNotNull(dispatcher);
120 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
121 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
122 this.localTables = ImmutableSet.copyOf(localTables);
123 this.localTablesKeys = new HashSet<TablesKey>();
124 this.dataBroker = dps;
125 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
126 this.extensions = Preconditions.checkNotNull(extensions);
127 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
128 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
129 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
130 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
131 this.configModuleTracker = moduleTracker;
132 this.openConfigProvider = openConfigProvider;
133 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
135 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
137 final ContainerNode bgpRib = Builders.containerBuilder()
138 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
139 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
141 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
142 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
143 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
144 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
145 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
146 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
150 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
152 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
153 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
154 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
157 trans.submit().checkedGet();
158 } catch (final TransactionCommitFailedException e) {
159 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
161 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
162 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
164 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
165 this.service = domDatatreeChangeService;
166 this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
167 LOG.debug("Effective RIB created.");
169 for (final BgpTableType t : this.localTables) {
170 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
171 this.localTablesKeys.add(key);
172 startLocRib(key, pd);
175 if (this.configModuleTracker != null) {
176 this.configModuleTracker.onInstanceCreate();
180 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
181 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
182 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
183 final GeneratedClassLoadingStrategy classStrategy) {
184 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, tcpStrategyFactory, codecFactory, sessionStrategyFactory,
185 dps, domDataBroker, localTables, classStrategy, null, null);
188 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
189 LOG.debug("Creating LocRib table for {}", key);
190 // create locRibWriter for each table
191 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
193 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
194 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
195 table.withChild(EMPTY_TABLE_ATTRIBUTES);
197 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
198 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
199 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
200 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
201 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
204 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
205 table.withChild(routes);
207 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
209 tx.submit().checkedGet();
210 } catch (final TransactionCommitFailedException e1) {
211 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
213 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
214 this.cacheDisconnectedPeers));
218 public String toString() {
219 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
222 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
223 return toStringHelper;
227 public synchronized void close() throws InterruptedException, ExecutionException {
228 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
229 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
231 this.domChain.close();
232 this.efWriter.close();
233 for (final LocRibWriter locRib : this.locRibs) {
236 } catch (final Exception e) {
237 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
240 if (this.configModuleTracker != null) {
241 this.configModuleTracker.onInstanceClose();
246 public AsNumber getLocalAs() {
251 public Ipv4Address getBgpIdentifier() {
252 return this.bgpIdentifier;
256 public Set<? extends BgpTableType> getLocalTables() {
257 return this.localTables;
261 public ReconnectStrategyFactory getTcpStrategyFactory() {
262 return this.tcpStrategyFactory;
266 public ReconnectStrategyFactory getSessionStrategyFactory() {
267 return this.sessionStrategyFactory;
271 public BGPDispatcher getDispatcher() {
272 return this.dispatcher;
276 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
277 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
281 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
282 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
286 public long getRoutesCount(final TablesKey key) {
287 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
288 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
289 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
290 if (tableMaybe.isPresent()) {
291 final Tables table = tableMaybe.get();
292 return countIpRoutes(table.getRoutes());
294 } catch (final ReadFailedException e) {
295 LOG.debug("Failed to read tables", e);
300 private int countIpRoutes(final Routes routes) {
301 if (routes instanceof Ipv4RoutesCase) {
302 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
303 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
304 return routesCase.getIpv4Routes().getIpv4Route().size();
306 } else if (routes instanceof Ipv6RoutesCase) {
307 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
308 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
309 return routesCase.getIpv6Routes().getIpv6Route().size();
315 public Set<TablesKey> getLocalTablesKeys() {
316 return this.localTablesKeys;
319 public DOMDataTreeChangeService getService() {
320 return (DOMDataTreeChangeService) this.service;
324 public YangInstanceIdentifier getYangRibId() {
325 return this.yangRibId;
329 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
330 return this.domDataBroker.createTransactionChain(listener);
334 public RIBExtensionConsumerContext getRibExtensions() {
335 return this.extensions;
339 public RIBSupportContextRegistry getRibSupportContext() {
340 return this.ribContextRegistry;
344 public void onGlobalContextUpdated(final SchemaContext context) {
345 this.codecsRegistry.onSchemaContextUpdated(context);
349 public CodecsRegistry getCodecsRegistry() {
350 return this.codecsRegistry;
354 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
355 return Optional.fromNullable(this.openConfigProvider);
359 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
360 return this.cacheDisconnectedPeers;