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;
20 import java.util.Map.Entry;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.ThreadSafe;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
38 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
39 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
40 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
41 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
42 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
48 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
49 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
66 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
67 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.common.QName;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
77 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
78 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
79 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
81 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
87 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
89 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
91 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);
93 private final BGPDispatcher dispatcher;
94 private final DOMTransactionChain domChain;
95 private final AsNumber localAs;
96 private final BgpId bgpIdentifier;
97 private final Set<BgpTableType> localTables;
98 private final Set<TablesKey> localTablesKeys;
99 private final DataBroker dataBroker;
100 private final DOMDataBroker domDataBroker;
101 private final RIBExtensionConsumerContext extensions;
102 private final YangInstanceIdentifier yangRibId;
103 private final RIBSupportContextRegistryImpl ribContextRegistry;
104 private final CodecsRegistryImpl codecsRegistry;
105 private final DOMDataBrokerExtension service;
106 private final List<LocRibWriter> locRibs = new ArrayList<>();
107 private final BGPConfigModuleTracker configModuleTracker;
108 private final BGPOpenConfigProvider openConfigProvider;
109 private final CacheDisconnectedPeers cacheDisconnectedPeers;
110 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
111 private final ImportPolicyPeerTracker importPolicyPeerTracker;
113 public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
114 final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
115 final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
116 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
117 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
118 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
119 this.domChain = domDataBroker.createTransactionChain(this);
120 this.localAs = Preconditions.checkNotNull(localAs);
121 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
122 this.dispatcher = Preconditions.checkNotNull(dispatcher);
123 this.localTables = ImmutableSet.copyOf(localTables);
124 this.localTablesKeys = new HashSet<>();
125 this.dataBroker = dps;
126 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
127 this.extensions = Preconditions.checkNotNull(extensions);
128 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
129 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
130 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
131 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
132 this.configModuleTracker = moduleTracker;
133 this.openConfigProvider = openConfigProvider;
134 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
135 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
137 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
139 final ContainerNode bgpRib = Builders.containerBuilder()
140 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
141 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
143 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
144 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
145 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
146 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
147 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
148 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
152 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
154 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
155 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
156 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
159 trans.submit().checkedGet();
160 } catch (final TransactionCommitFailedException e) {
161 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
163 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
164 final PolicyDatabase policyDatabase = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
165 this.importPolicyPeerTracker = new ImportPolicyPeerTracker(policyDatabase);
167 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
168 this.service = domDatatreeChangeService;
169 LOG.debug("Effective RIB created.");
171 for (final BgpTableType t : this.localTables) {
172 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
173 this.localTablesKeys.add(key);
174 startLocRib(key, policyDatabase);
177 if (this.configModuleTracker != null) {
178 this.configModuleTracker.onInstanceCreate();
182 public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
183 final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
184 final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
185 final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
186 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
187 dps, domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
190 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
191 LOG.debug("Creating LocRib table for {}", key);
192 // create locRibWriter for each table
193 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
195 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
196 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
197 table.withChild(EMPTY_TABLE_ATTRIBUTES);
199 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
200 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
201 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
202 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
203 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
206 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
207 table.withChild(routes);
209 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
211 tx.submit().checkedGet();
212 } catch (final TransactionCommitFailedException e1) {
213 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
216 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
217 if (pathSelectionStrategy == null) {
218 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
220 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
221 this.cacheDisconnectedPeers, pathSelectionStrategy));
225 public String toString() {
226 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
229 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
230 return toStringHelper;
234 public synchronized void close() throws InterruptedException, ExecutionException {
235 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
236 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
238 this.domChain.close();
239 for (final LocRibWriter locRib : this.locRibs) {
242 } catch (final Exception e) {
243 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
246 if (this.configModuleTracker != null) {
247 this.configModuleTracker.onInstanceClose();
252 public AsNumber getLocalAs() {
257 public BgpId getBgpIdentifier() {
258 return this.bgpIdentifier;
262 public Set<? extends BgpTableType> getLocalTables() {
263 return this.localTables;
267 public BGPDispatcher getDispatcher() {
268 return this.dispatcher;
272 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
273 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
277 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
278 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
282 public long getRoutesCount(final TablesKey key) {
283 try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
284 final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
285 getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
286 if (tableMaybe.isPresent()) {
287 final Tables table = tableMaybe.get();
288 return countIpRoutes(table.getRoutes());
290 } catch (final ReadFailedException e) {
291 LOG.debug("Failed to read tables", e);
296 private int countIpRoutes(final Routes routes) {
297 if (routes instanceof Ipv4RoutesCase) {
298 final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes;
299 if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
300 return routesCase.getIpv4Routes().getIpv4Route().size();
302 } else if (routes instanceof Ipv6RoutesCase) {
303 final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes;
304 if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
305 return routesCase.getIpv6Routes().getIpv6Route().size();
311 public Set<TablesKey> getLocalTablesKeys() {
312 return this.localTablesKeys;
316 public DOMDataTreeChangeService getService() {
317 return (DOMDataTreeChangeService) this.service;
321 public YangInstanceIdentifier getYangRibId() {
322 return this.yangRibId;
326 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
327 return this.domDataBroker.createTransactionChain(listener);
331 public RIBExtensionConsumerContext getRibExtensions() {
332 return this.extensions;
336 public RIBSupportContextRegistry getRibSupportContext() {
337 return this.ribContextRegistry;
341 public void onGlobalContextUpdated(final SchemaContext context) {
342 this.codecsRegistry.onSchemaContextUpdated(context);
346 public CodecsRegistry getCodecsRegistry() {
347 return this.codecsRegistry;
351 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
352 return Optional.fromNullable(this.openConfigProvider);
356 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
357 return this.cacheDisconnectedPeers;
360 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
361 return this.importPolicyPeerTracker;