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.rev100924.AsNumber;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.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.ClusterIdentifier;
65 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
66 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
73 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
76 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
77 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
78 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
79 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
85 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
86 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
88 public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
90 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);
92 private final BGPDispatcher dispatcher;
93 private final DOMTransactionChain domChain;
94 private final AsNumber localAs;
95 private final Ipv4Address bgpIdentifier;
96 private final Set<BgpTableType> localTables;
97 private final Set<TablesKey> localTablesKeys;
98 private final DataBroker dataBroker;
99 private final DOMDataBroker domDataBroker;
100 private final RIBExtensionConsumerContext extensions;
101 private final YangInstanceIdentifier yangRibId;
102 private final RIBSupportContextRegistryImpl ribContextRegistry;
103 private final CodecsRegistryImpl codecsRegistry;
104 private final DOMDataBrokerExtension service;
105 private final List<LocRibWriter> locRibs = new ArrayList<>();
106 private final BGPConfigModuleTracker configModuleTracker;
107 private final BGPOpenConfigProvider openConfigProvider;
108 private final CacheDisconnectedPeers cacheDisconnectedPeers;
109 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
110 private final ImportPolicyPeerTracker importPolicyPeerTracker;
112 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
113 final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
114 final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
115 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
116 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
117 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
118 this.domChain = domDataBroker.createTransactionChain(this);
119 this.localAs = Preconditions.checkNotNull(localAs);
120 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
121 this.dispatcher = Preconditions.checkNotNull(dispatcher);
122 this.localTables = ImmutableSet.copyOf(localTables);
123 this.localTablesKeys = new HashSet<>();
124 this.dataBroker = dps;
125 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
126 this.extensions = Preconditions.checkNotNull(extensions);
127 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
128 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
129 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
130 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
131 this.configModuleTracker = moduleTracker;
132 this.openConfigProvider = openConfigProvider;
133 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
134 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
136 LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
138 final ContainerNode bgpRib = Builders.containerBuilder()
139 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
140 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
142 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
143 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
144 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
145 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
146 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
147 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
151 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
153 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
154 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
155 trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
158 trans.submit().checkedGet();
159 } catch (final TransactionCommitFailedException e) {
160 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
162 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
163 final PolicyDatabase policyDatabase = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
164 this.importPolicyPeerTracker = new ImportPolicyPeerTracker(policyDatabase);
166 final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
167 this.service = domDatatreeChangeService;
168 LOG.debug("Effective RIB created.");
170 for (final BgpTableType t : this.localTables) {
171 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
172 this.localTablesKeys.add(key);
173 startLocRib(key, policyDatabase);
176 if (this.configModuleTracker != null) {
177 this.configModuleTracker.onInstanceCreate();
181 public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
182 final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
183 final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
184 final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
185 this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
186 dps, domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
189 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
190 LOG.debug("Creating LocRib table for {}", key);
191 // create locRibWriter for each table
192 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
194 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
195 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
196 table.withChild(EMPTY_TABLE_ATTRIBUTES);
198 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
199 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
200 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
201 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
202 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
205 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
206 table.withChild(routes);
208 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
210 tx.submit().checkedGet();
211 } catch (final TransactionCommitFailedException e1) {
212 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
215 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
216 if (pathSelectionStrategy == null) {
217 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
219 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
220 this.cacheDisconnectedPeers, pathSelectionStrategy));
224 public String toString() {
225 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
228 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
229 return toStringHelper;
233 public synchronized void close() throws InterruptedException, ExecutionException {
234 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
235 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
237 this.domChain.close();
238 for (final LocRibWriter locRib : this.locRibs) {
241 } catch (final Exception e) {
242 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
245 if (this.configModuleTracker != null) {
246 this.configModuleTracker.onInstanceClose();
251 public AsNumber getLocalAs() {
256 public Ipv4Address getBgpIdentifier() {
257 return this.bgpIdentifier;
261 public Set<? extends BgpTableType> getLocalTables() {
262 return this.localTables;
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;
315 public DOMDataTreeChangeService getService() {
316 return (DOMDataTreeChangeService) this.service;
320 public YangInstanceIdentifier getYangRibId() {
321 return this.yangRibId;
325 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
326 return this.domDataBroker.createTransactionChain(listener);
330 public RIBExtensionConsumerContext getRibExtensions() {
331 return this.extensions;
335 public RIBSupportContextRegistry getRibSupportContext() {
336 return this.ribContextRegistry;
340 public void onGlobalContextUpdated(final SchemaContext context) {
341 this.codecsRegistry.onSchemaContextUpdated(context);
345 public CodecsRegistry getCodecsRegistry() {
346 return this.codecsRegistry;
350 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
351 return Optional.fromNullable(this.openConfigProvider);
355 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
356 return this.cacheDisconnectedPeers;
359 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
360 return this.importPolicyPeerTracker;