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.rib.DefaultRibReference;
37 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
38 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
40 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
41 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
42 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
57 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
58 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
65 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
68 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
69 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
70 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
71 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
77 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
78 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
80 public static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
82 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);
84 private final ReconnectStrategyFactory tcpStrategyFactory;
85 private final ReconnectStrategyFactory sessionStrategyFactory;
87 private final BGPDispatcher dispatcher;
88 private final DOMTransactionChain domChain;
89 private final AsNumber localAs;
90 private final Ipv4Address bgpIdentifier;
91 private final Set<BgpTableType> localTables;
92 private final Set<TablesKey> localTablesKeys;
93 private final DataBroker dataBroker;
94 private final DOMDataBroker domDataBroker;
95 private final RIBExtensionConsumerContext extensions;
96 private final YangInstanceIdentifier yangRibId;
97 private final RIBSupportContextRegistryImpl ribContextRegistry;
98 private final EffectiveRibInWriter efWriter;
99 private final DOMDataBrokerExtension service;
100 private final List<LocRibWriter> locRibs = new ArrayList<>();
102 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
103 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
104 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
105 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
106 this.domChain = domDataBroker.createTransactionChain(this);
107 this.localAs = Preconditions.checkNotNull(localAs);
108 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
109 this.dispatcher = Preconditions.checkNotNull(dispatcher);
110 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
111 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
112 this.localTables = ImmutableSet.copyOf(localTables);
113 this.localTablesKeys = new HashSet<TablesKey>();
114 this.dataBroker = dps;
115 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
116 this.extensions = Preconditions.checkNotNull(extensions);
117 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
118 this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
120 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
122 final ContainerNode rib = Builders.containerBuilder()
123 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
124 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
125 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
126 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
127 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
128 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
129 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
136 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
138 // put empty BgpRib if not exists
139 trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
142 trans.submit().checkedGet();
143 } catch (final TransactionCommitFailedException e) {
144 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
146 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
147 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
149 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
150 this.service = domDatatreeChangeService;
151 this.efWriter = EffectiveRibInWriter.create(getService(), this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
152 LOG.debug("Effective RIB created.");
154 for (final BgpTableType t : this.localTables) {
155 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
156 this.localTablesKeys.add(key);
157 startLocRib(key, pd);
161 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
162 LOG.debug("Creating LocRib table for {}", key);
163 // create locRibWriter for each table
164 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
166 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
167 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
168 table.withChild(EMPTY_TABLE_ATTRIBUTES);
170 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
171 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
172 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
173 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
174 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
177 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
178 table.withChild(routes);
180 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
182 tx.submit().checkedGet();
183 } catch (final TransactionCommitFailedException e1) {
184 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
186 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), this.localAs, getService(), pd));
190 public String toString() {
191 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
194 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
195 return toStringHelper;
199 public synchronized void close() throws InterruptedException, ExecutionException {
200 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
201 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
203 this.domChain.close();
204 this.efWriter.close();
205 for (final LocRibWriter locRib : this.locRibs) {
208 } catch (final Exception e) {
209 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
215 public AsNumber getLocalAs() {
220 public Ipv4Address getBgpIdentifier() {
221 return this.bgpIdentifier;
225 public Set<? extends BgpTableType> getLocalTables() {
226 return this.localTables;
230 public ReconnectStrategyFactory getTcpStrategyFactory() {
231 return this.tcpStrategyFactory;
235 public ReconnectStrategyFactory getSessionStrategyFactory() {
236 return this.sessionStrategyFactory;
240 public BGPDispatcher getDispatcher() {
241 return this.dispatcher;
245 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
246 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
250 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
251 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
255 public long getRoutesCount(final TablesKey key) {
256 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
257 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
258 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
259 if (tableMaybe.isPresent()) {
260 final Tables table = tableMaybe.get();
261 if (table.getRoutes() instanceof Ipv4RoutesCase) {
262 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
263 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
264 return routesCase.getIpv4Routes().getIpv4Route().size();
266 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
267 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
268 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
269 return routesCase.getIpv6Routes().getIpv6Route().size();
273 } catch (final ReadFailedException e) {
274 LOG.debug("Failed to read tables", e);
279 public Set<TablesKey> getLocalTablesKeys() {
280 return this.localTablesKeys;
283 public DOMDataTreeChangeService getService() {
284 return (DOMDataTreeChangeService) this.service;
288 public YangInstanceIdentifier getYangRibId() {
289 return this.yangRibId;
293 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
294 return this.domDataBroker.createTransactionChain(listener);
298 public RIBExtensionConsumerContext getRibExtensions() {
299 return this.extensions;
303 public RIBSupportContextRegistry getRibSupportContext() {
304 return this.ribContextRegistry;
308 public void onGlobalContextUpdated(final SchemaContext context) {
309 this.ribContextRegistry.onSchemaContextUpdated(context);