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.openconfig.spi.BGPConfigModuleTracker;
37 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
38 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
41 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
43 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
44 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
45 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
61 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
62 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.opendaylight.yangtools.yang.common.QName;
65 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
66 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
67 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
69 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
70 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
71 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
72 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
73 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
74 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
75 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
76 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
82 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
84 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
86 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);
88 private final ReconnectStrategyFactory tcpStrategyFactory;
89 private final ReconnectStrategyFactory sessionStrategyFactory;
91 private final BGPDispatcher dispatcher;
92 private final DOMTransactionChain domChain;
93 private final AsNumber localAs;
94 private final Ipv4Address bgpIdentifier;
95 private final Set<BgpTableType> localTables;
96 private final Set<TablesKey> localTablesKeys;
97 private final DataBroker dataBroker;
98 private final DOMDataBroker domDataBroker;
99 private final RIBExtensionConsumerContext extensions;
100 private final YangInstanceIdentifier yangRibId;
101 private final RIBSupportContextRegistryImpl ribContextRegistry;
102 private final CodecsRegistryImpl codecsRegistry;
103 private final EffectiveRibInWriter efWriter;
104 private final DOMDataBrokerExtension service;
105 private final List<LocRibWriter> locRibs = new ArrayList<>();
106 private final BGPConfigModuleTracker configModuleTracker;
107 private final BGPOpenConfigProvider openConfigProvider;
109 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
110 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
111 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
112 final GeneratedClassLoadingStrategy classStrategy, final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
113 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
114 this.domChain = domDataBroker.createTransactionChain(this);
115 this.localAs = Preconditions.checkNotNull(localAs);
116 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
117 this.dispatcher = Preconditions.checkNotNull(dispatcher);
118 this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
119 this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
120 this.localTables = ImmutableSet.copyOf(localTables);
121 this.localTablesKeys = new HashSet<TablesKey>();
122 this.dataBroker = dps;
123 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
124 this.extensions = Preconditions.checkNotNull(extensions);
125 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
126 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
127 this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
128 this.configModuleTracker = moduleTracker;
129 this.openConfigProvider = openConfigProvider;
131 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
133 final ContainerNode rib = Builders.containerBuilder()
134 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
135 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
136 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
137 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
138 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
139 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
140 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
147 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
149 // put empty BgpRib if not exists
150 trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
153 trans.submit().checkedGet();
154 } catch (final TransactionCommitFailedException e) {
155 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
157 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
158 final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
160 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
161 this.service = domDatatreeChangeService;
162 this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
163 LOG.debug("Effective RIB created.");
165 for (final BgpTableType t : this.localTables) {
166 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
167 this.localTablesKeys.add(key);
168 startLocRib(key, pd);
171 if (this.configModuleTracker != null) {
172 this.configModuleTracker.onInstanceCreate();
176 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
177 final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
178 final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
179 final GeneratedClassLoadingStrategy classStrategy) {
180 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, tcpStrategyFactory, codecFactory, sessionStrategyFactory,
181 dps, domDataBroker, localTables, classStrategy, null, null);
184 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
185 LOG.debug("Creating LocRib table for {}", key);
186 // create locRibWriter for each table
187 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
189 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
190 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
191 table.withChild(EMPTY_TABLE_ATTRIBUTES);
193 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
194 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
195 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
196 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
197 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
200 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
201 table.withChild(routes);
203 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
205 tx.submit().checkedGet();
206 } catch (final TransactionCommitFailedException e1) {
207 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
209 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd));
213 public String toString() {
214 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
217 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
218 return toStringHelper;
222 public synchronized void close() throws InterruptedException, ExecutionException {
223 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
224 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
226 this.domChain.close();
227 this.efWriter.close();
228 for (final LocRibWriter locRib : this.locRibs) {
231 } catch (final Exception e) {
232 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
235 if (this.configModuleTracker != null) {
236 this.configModuleTracker.onInstanceClose();
241 public AsNumber getLocalAs() {
246 public Ipv4Address getBgpIdentifier() {
247 return this.bgpIdentifier;
251 public Set<? extends BgpTableType> getLocalTables() {
252 return this.localTables;
256 public ReconnectStrategyFactory getTcpStrategyFactory() {
257 return this.tcpStrategyFactory;
261 public ReconnectStrategyFactory getSessionStrategyFactory() {
262 return this.sessionStrategyFactory;
266 public BGPDispatcher getDispatcher() {
267 return this.dispatcher;
271 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
272 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
276 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
277 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
281 public long getRoutesCount(final TablesKey key) {
282 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
283 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
284 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
285 if (tableMaybe.isPresent()) {
286 final Tables table = tableMaybe.get();
287 return countIpRoutes(table.getRoutes());
289 } catch (final ReadFailedException e) {
290 LOG.debug("Failed to read tables", e);
295 private int countIpRoutes(final Routes routes) {
296 if (routes instanceof Ipv4RoutesCase) {
297 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
298 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
299 return routesCase.getIpv4Routes().getIpv4Route().size();
301 } else if (routes instanceof Ipv6RoutesCase) {
302 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
303 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
304 return routesCase.getIpv6Routes().getIpv6Route().size();
310 public Set<TablesKey> getLocalTablesKeys() {
311 return this.localTablesKeys;
314 public DOMDataTreeChangeService getService() {
315 return (DOMDataTreeChangeService) this.service;
319 public YangInstanceIdentifier getYangRibId() {
320 return this.yangRibId;
324 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
325 return this.domDataBroker.createTransactionChain(listener);
329 public RIBExtensionConsumerContext getRibExtensions() {
330 return this.extensions;
334 public RIBSupportContextRegistry getRibSupportContext() {
335 return this.ribContextRegistry;
339 public void onGlobalContextUpdated(final SchemaContext context) {
340 this.codecsRegistry.onSchemaContextUpdated(context);
344 public CodecsRegistry getCodecsRegistry() {
345 return this.codecsRegistry;
349 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
350 return Optional.fromNullable(this.openConfigProvider);