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.RIB;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
40 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
41 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
42 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
58 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
59 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.common.QName;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
65 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
66 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
68 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
69 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
70 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
71 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
73 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
78 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
79 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
81 public static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
83 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);
85 private final ReconnectStrategyFactory tcpStrategyFactory;
86 private final ReconnectStrategyFactory sessionStrategyFactory;
88 private final BGPDispatcher dispatcher;
89 private final DOMTransactionChain domChain;
90 private final AsNumber localAs;
91 private final Ipv4Address bgpIdentifier;
92 private final Set<BgpTableType> localTables;
93 private final Set<TablesKey> localTablesKeys;
94 private final DataBroker dataBroker;
95 private final DOMDataBroker domDataBroker;
96 private final RIBExtensionConsumerContext extensions;
97 private final YangInstanceIdentifier yangRibId;
98 private final RIBSupportContextRegistryImpl ribContextRegistry;
99 private final EffectiveRibInWriter efWriter;
100 private final DOMDataBrokerExtension service;
101 private final List<LocRibWriter> locRibs = new ArrayList<>();
103 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
104 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
105 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
106 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
107 this.domChain = domDataBroker.createTransactionChain(this);
108 this.localAs = Preconditions.checkNotNull(localAs);
109 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
110 this.dispatcher = Preconditions.checkNotNull(dispatcher);
111 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
112 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
113 this.localTables = ImmutableSet.copyOf(localTables);
114 this.localTablesKeys = new HashSet<TablesKey>();
115 this.dataBroker = dps;
116 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
117 this.extensions = Preconditions.checkNotNull(extensions);
118 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
119 this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
121 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
123 final ContainerNode rib = Builders.containerBuilder()
124 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
125 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
126 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
127 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
128 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
129 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
130 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
137 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
139 // put empty BgpRib if not exists
140 trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
143 trans.submit().checkedGet();
144 } catch (final TransactionCommitFailedException e) {
145 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
147 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
148 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
150 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
151 this.service = domDatatreeChangeService;
152 this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
153 LOG.debug("Effective RIB created.");
155 for (final BgpTableType t : this.localTables) {
156 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
157 this.localTablesKeys.add(key);
158 startLocRib(key, pd);
162 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
163 LOG.debug("Creating LocRib table for {}", key);
164 // create locRibWriter for each table
165 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
167 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
168 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
169 table.withChild(EMPTY_TABLE_ATTRIBUTES);
171 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
172 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
173 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
174 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
175 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
178 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
179 table.withChild(routes);
181 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
183 tx.submit().checkedGet();
184 } catch (final TransactionCommitFailedException e1) {
185 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
187 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd));
191 public String toString() {
192 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
195 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
196 return toStringHelper;
200 public synchronized void close() throws InterruptedException, ExecutionException {
201 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
202 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
204 this.domChain.close();
205 this.efWriter.close();
206 for (final LocRibWriter locRib : this.locRibs) {
209 } catch (final Exception e) {
210 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
216 public AsNumber getLocalAs() {
221 public Ipv4Address getBgpIdentifier() {
222 return this.bgpIdentifier;
226 public Set<? extends BgpTableType> getLocalTables() {
227 return this.localTables;
231 public ReconnectStrategyFactory getTcpStrategyFactory() {
232 return this.tcpStrategyFactory;
236 public ReconnectStrategyFactory getSessionStrategyFactory() {
237 return this.sessionStrategyFactory;
241 public BGPDispatcher getDispatcher() {
242 return this.dispatcher;
246 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
247 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
251 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
252 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
256 public long getRoutesCount(final TablesKey key) {
257 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
258 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
259 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
260 if (tableMaybe.isPresent()) {
261 final Tables table = tableMaybe.get();
262 return countIpRoutes(table.getRoutes());
264 } catch (final ReadFailedException e) {
265 LOG.debug("Failed to read tables", e);
270 private int countIpRoutes(final Routes routes) {
271 if (routes instanceof Ipv4RoutesCase) {
272 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
273 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
274 return routesCase.getIpv4Routes().getIpv4Route().size();
276 } else if (routes instanceof Ipv6RoutesCase) {
277 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
278 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
279 return routesCase.getIpv6Routes().getIpv6Route().size();
285 public Set<TablesKey> getLocalTablesKeys() {
286 return this.localTablesKeys;
289 public DOMDataTreeChangeService getService() {
290 return (DOMDataTreeChangeService) this.service;
294 public YangInstanceIdentifier getYangRibId() {
295 return this.yangRibId;
299 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
300 return this.domDataBroker.createTransactionChain(listener);
304 public RIBExtensionConsumerContext getRibExtensions() {
305 return this.extensions;
309 public RIBSupportContextRegistry getRibSupportContext() {
310 return this.ribContextRegistry;
314 public void onGlobalContextUpdated(final SchemaContext context) {
315 this.ribContextRegistry.onSchemaContextUpdated(context);