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 domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
147 this.service = domDatatreeChangeService;
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);
183 LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), this.localAs, getService(), pd);
187 public String toString() {
188 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
191 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
192 return toStringHelper;
196 public synchronized void close() throws InterruptedException, ExecutionException {
197 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
198 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
200 this.domChain.close();
201 this.efWriter.close();
205 public AsNumber getLocalAs() {
210 public Ipv4Address getBgpIdentifier() {
211 return this.bgpIdentifier;
215 public Set<? extends BgpTableType> getLocalTables() {
216 return this.localTables;
220 public ReconnectStrategyFactory getTcpStrategyFactory() {
221 return this.tcpStrategyFactory;
225 public ReconnectStrategyFactory getSessionStrategyFactory() {
226 return this.sessionStrategyFactory;
230 public BGPDispatcher getDispatcher() {
231 return this.dispatcher;
235 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
236 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
240 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
241 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
245 public long getRoutesCount(final TablesKey key) {
246 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
247 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
248 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
249 if (tableMaybe.isPresent()) {
250 final Tables table = tableMaybe.get();
251 if (table.getRoutes() instanceof Ipv4RoutesCase) {
252 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
253 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
254 return routesCase.getIpv4Routes().getIpv4Route().size();
256 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
257 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
258 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
259 return routesCase.getIpv6Routes().getIpv6Route().size();
263 } catch (final ReadFailedException e) {
264 LOG.debug("Failed to read tables", e);
269 public Set<TablesKey> getLocalTablesKeys() {
270 return this.localTablesKeys;
273 public DOMDataTreeChangeService getService() {
274 return (DOMDataTreeChangeService) this.service;
278 public YangInstanceIdentifier getYangRibId() {
279 return this.yangRibId;
283 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
284 return this.domDataBroker.createTransactionChain(listener);
288 public RIBExtensionConsumerContext getRibExtensions() {
289 return this.extensions;
293 public RIBSupportContextRegistry getRibSupportContext() {
294 return this.ribContextRegistry;
298 public void onGlobalContextUpdated(final SchemaContext context) {
299 this.ribContextRegistry.onSchemaContextUpdated(context);