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 Set<BgpTableType> localTables;
88 private final Set<TablesKey> localTablesKeys;
89 private final DataBroker dataBroker;
90 private final DOMDataBroker domDataBroker;
91 private final RIBExtensionConsumerContext extensions;
92 private final YangInstanceIdentifier yangRibId;
93 private final RIBSupportContextRegistryImpl ribContextRegistry;
94 private final EffectiveRibInWriter efWriter;
95 private final DOMDataBrokerExtension service;
97 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
98 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
99 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
100 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
101 this.domChain = domDataBroker.createTransactionChain(this);
102 this.localAs = Preconditions.checkNotNull(localAs);
103 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
104 this.dispatcher = Preconditions.checkNotNull(dispatcher);
105 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
106 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
107 this.localTables = ImmutableSet.copyOf(localTables);
108 this.localTablesKeys = new HashSet<TablesKey>();
109 this.dataBroker = dps;
110 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
111 this.extensions = Preconditions.checkNotNull(extensions);
112 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
113 this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
115 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
117 final ContainerNode rib = Builders.containerBuilder()
118 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
119 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
120 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
121 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
122 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
123 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
124 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
131 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
133 // put empty BgpRib if not exists
134 trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
137 trans.submit().checkedGet();
138 } catch (final TransactionCommitFailedException e) {
139 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
141 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
142 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
144 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
145 this.service = domDatatreeChangeService;
146 this.efWriter = EffectiveRibInWriter.create(getService(), this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
147 LOG.debug("Effective RIB created.");
149 for (final BgpTableType t : this.localTables) {
150 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
151 this.localTablesKeys.add(key);
152 startLocRib(key, pd);
156 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
157 LOG.debug("Creating LocRib table for {}", key);
158 // create locRibWriter for each table
159 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
161 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
162 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
163 table.withChild(EMPTY_TABLE_ATTRIBUTES);
165 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
166 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
167 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
168 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
169 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
172 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
173 table.withChild(routes);
175 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
177 tx.submit().checkedGet();
178 } catch (final TransactionCommitFailedException e1) {
179 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
182 // FIXME: do not lose the writer so we clean it up on shutdown
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);