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