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.RIBExtensionConsumerContext;
44 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
45 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
61 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
62 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
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 DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
82 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
84 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
86 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);
88 private final ReconnectStrategyFactory tcpStrategyFactory;
89 private final ReconnectStrategyFactory sessionStrategyFactory;
91 private final BGPDispatcher dispatcher;
92 private final DOMTransactionChain domChain;
93 private final AsNumber localAs;
94 private final Ipv4Address bgpIdentifier;
95 private final Set<BgpTableType> localTables;
96 private final Set<TablesKey> localTablesKeys;
97 private final DataBroker dataBroker;
98 private final DOMDataBroker domDataBroker;
99 private final RIBExtensionConsumerContext extensions;
100 private final YangInstanceIdentifier yangRibId;
101 private final RIBSupportContextRegistryImpl ribContextRegistry;
102 private final CodecsRegistryImpl codecsRegistry;
103 private final EffectiveRibInWriter efWriter;
104 private final DOMDataBrokerExtension service;
105 private final List<LocRibWriter> locRibs = new ArrayList<>();
106 private final BGPConfigModuleTracker configModuleTracker;
107 private final BGPOpenConfigProvider openConfigProvider;
109 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
110 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
111 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
112 final GeneratedClassLoadingStrategy classStrategy, final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
113 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
114 this.domChain = domDataBroker.createTransactionChain(this);
115 this.localAs = Preconditions.checkNotNull(localAs);
116 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
117 this.dispatcher = Preconditions.checkNotNull(dispatcher);
118 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
119 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
120 this.localTables = ImmutableSet.copyOf(localTables);
121 this.localTablesKeys = new HashSet<TablesKey>();
122 this.dataBroker = dps;
123 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
124 this.extensions = Preconditions.checkNotNull(extensions);
125 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
126 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
127 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
128 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
129 this.configModuleTracker = moduleTracker;
130 this.openConfigProvider = openConfigProvider;
132 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
134 final ContainerNode bgpRib = Builders.containerBuilder()
135 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
136 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
138 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
139 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
140 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
141 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
142 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
143 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
147 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
149 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
150 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
151 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
154 trans.submit().checkedGet();
155 } catch (final TransactionCommitFailedException e) {
156 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
158 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
159 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
161 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
162 this.service = domDatatreeChangeService;
163 this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
164 LOG.debug("Effective RIB created.");
166 for (final BgpTableType t : this.localTables) {
167 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
168 this.localTablesKeys.add(key);
169 startLocRib(key, pd);
172 if (this.configModuleTracker != null) {
173 this.configModuleTracker.onInstanceCreate();
177 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
178 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
179 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
180 final GeneratedClassLoadingStrategy classStrategy) {
181 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, tcpStrategyFactory, codecFactory, sessionStrategyFactory,
182 dps, domDataBroker, localTables, classStrategy, null, null);
185 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
186 LOG.debug("Creating LocRib table for {}", key);
187 // create locRibWriter for each table
188 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
190 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
191 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
192 table.withChild(EMPTY_TABLE_ATTRIBUTES);
194 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
195 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
196 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
197 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
198 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
201 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
202 table.withChild(routes);
204 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
206 tx.submit().checkedGet();
207 } catch (final TransactionCommitFailedException e1) {
208 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
210 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd));
214 public String toString() {
215 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
218 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
219 return toStringHelper;
223 public synchronized void close() throws InterruptedException, ExecutionException {
224 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
225 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
227 this.domChain.close();
228 this.efWriter.close();
229 for (final LocRibWriter locRib : this.locRibs) {
232 } catch (final Exception e) {
233 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
236 if (this.configModuleTracker != null) {
237 this.configModuleTracker.onInstanceClose();
242 public AsNumber getLocalAs() {
247 public Ipv4Address getBgpIdentifier() {
248 return this.bgpIdentifier;
252 public Set<? extends BgpTableType> getLocalTables() {
253 return this.localTables;
257 public ReconnectStrategyFactory getTcpStrategyFactory() {
258 return this.tcpStrategyFactory;
262 public ReconnectStrategyFactory getSessionStrategyFactory() {
263 return this.sessionStrategyFactory;
267 public BGPDispatcher getDispatcher() {
268 return this.dispatcher;
272 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
273 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
277 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
278 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
282 public long getRoutesCount(final TablesKey key) {
283 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
284 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
285 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
286 if (tableMaybe.isPresent()) {
287 final Tables table = tableMaybe.get();
288 return countIpRoutes(table.getRoutes());
290 } catch (final ReadFailedException e) {
291 LOG.debug("Failed to read tables", e);
296 private int countIpRoutes(final Routes routes) {
297 if (routes instanceof Ipv4RoutesCase) {
298 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
299 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
300 return routesCase.getIpv4Routes().getIpv4Route().size();
302 } else if (routes instanceof Ipv6RoutesCase) {
303 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
304 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
305 return routesCase.getIpv6Routes().getIpv6Route().size();
311 public Set<TablesKey> getLocalTablesKeys() {
312 return this.localTablesKeys;
315 public DOMDataTreeChangeService getService() {
316 return (DOMDataTreeChangeService) this.service;
320 public YangInstanceIdentifier getYangRibId() {
321 return this.yangRibId;
325 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
326 return this.domDataBroker.createTransactionChain(listener);
330 public RIBExtensionConsumerContext getRibExtensions() {
331 return this.extensions;
335 public RIBSupportContextRegistry getRibSupportContext() {
336 return this.ribContextRegistry;
340 public void onGlobalContextUpdated(final SchemaContext context) {
341 this.codecsRegistry.onSchemaContextUpdated(context);
345 public CodecsRegistry getCodecsRegistry() {
346 return this.codecsRegistry;
350 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
351 return Optional.fromNullable(this.openConfigProvider);