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.HashSet;
17 import java.util.List;
18 import java.util.Map.Entry;
20 import java.util.concurrent.ExecutionException;
21 import javax.annotation.concurrent.ThreadSafe;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
35 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
36 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
37 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
38 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
39 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
40 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
41 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
56 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
57 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
64 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
65 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
67 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
68 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
69 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
70 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
71 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
76 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
77 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
79 public static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
81 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);
83 private final ReconnectStrategyFactory tcpStrategyFactory;
84 private final ReconnectStrategyFactory sessionStrategyFactory;
86 private final BGPDispatcher dispatcher;
87 private final DOMTransactionChain domChain;
88 private final AsNumber localAs;
89 private final Ipv4Address bgpIdentifier;
90 private final Set<BgpTableType> localTables;
91 private final Set<TablesKey> localTablesKeys;
92 private final DataBroker dataBroker;
93 private final DOMDataBroker domDataBroker;
94 private final RIBExtensionConsumerContext extensions;
95 private final YangInstanceIdentifier yangRibId;
96 private final RIBSupportContextRegistryImpl ribContextRegistry;
97 private final EffectiveRibInWriter efWriter;
98 private final DOMDataBrokerExtension service;
100 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
101 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
102 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
103 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
104 this.domChain = domDataBroker.createTransactionChain(this);
105 this.localAs = Preconditions.checkNotNull(localAs);
106 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
107 this.dispatcher = Preconditions.checkNotNull(dispatcher);
108 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
109 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
110 this.localTables = ImmutableSet.copyOf(localTables);
111 this.localTablesKeys = new HashSet<TablesKey>();
112 this.dataBroker = dps;
113 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
114 this.extensions = Preconditions.checkNotNull(extensions);
115 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
116 this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
118 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
120 final ContainerNode rib = Builders.containerBuilder()
121 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
122 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
123 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
124 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
125 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
126 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
127 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
134 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
136 // put empty BgpRib if not exists
137 trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
140 trans.submit().checkedGet();
141 } catch (final TransactionCommitFailedException e) {
142 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
144 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
145 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
147 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
148 this.service = domDatatreeChangeService;
149 this.efWriter = EffectiveRibInWriter.create(getService(), this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
150 LOG.debug("Effective RIB created.");
152 for (final BgpTableType t : this.localTables) {
153 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
154 this.localTablesKeys.add(key);
155 startLocRib(key, pd);
159 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
160 LOG.debug("Creating LocRib table for {}", key);
161 // create locRibWriter for each table
162 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
164 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
165 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
166 table.withChild(EMPTY_TABLE_ATTRIBUTES);
168 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
169 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
170 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
171 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
172 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
175 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
176 table.withChild(routes);
178 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
180 tx.submit().checkedGet();
181 } catch (final TransactionCommitFailedException e1) {
182 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
185 // FIXME: do not lose the writer so we clean it up on shutdown
186 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();
208 public AsNumber getLocalAs() {
213 public Ipv4Address getBgpIdentifier() {
214 return this.bgpIdentifier;
218 public Set<? extends BgpTableType> getLocalTables() {
219 return this.localTables;
223 public ReconnectStrategyFactory getTcpStrategyFactory() {
224 return this.tcpStrategyFactory;
228 public ReconnectStrategyFactory getSessionStrategyFactory() {
229 return this.sessionStrategyFactory;
233 public BGPDispatcher getDispatcher() {
234 return this.dispatcher;
238 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
239 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
243 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
244 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
248 public long getRoutesCount(final TablesKey key) {
249 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
250 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
251 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
252 if (tableMaybe.isPresent()) {
253 final Tables table = tableMaybe.get();
254 if (table.getRoutes() instanceof Ipv4RoutesCase) {
255 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
256 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
257 return routesCase.getIpv4Routes().getIpv4Route().size();
259 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
260 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
261 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
262 return routesCase.getIpv6Routes().getIpv6Route().size();
266 } catch (final ReadFailedException e) {
267 LOG.debug("Failed to read tables", e);
272 public Set<TablesKey> getLocalTablesKeys() {
273 return this.localTablesKeys;
276 public DOMDataTreeChangeService getService() {
277 return (DOMDataTreeChangeService) this.service;
281 public YangInstanceIdentifier getYangRibId() {
282 return this.yangRibId;
286 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
287 return this.domDataBroker.createTransactionChain(listener);
291 public RIBExtensionConsumerContext getRibExtensions() {
292 return this.extensions;
296 public RIBSupportContextRegistry getRibSupportContext() {
297 return this.ribContextRegistry;
301 public void onGlobalContextUpdated(final SchemaContext context) {
302 this.ribContextRegistry.onSchemaContextUpdated(context);