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