BUG-2383: Added wiring of Attributes codecs to RibSupportContext
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / RIBImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.rib.impl;
9
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 com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Set;
21 import java.util.concurrent.BlockingQueue;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.LinkedBlockingQueue;
26 import javax.annotation.concurrent.ThreadSafe;
27 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
36 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
37 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
38 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
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.AbstractAdjRIBs;
44 import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn;
45 import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator;
46 import org.opendaylight.protocol.bgp.rib.spi.Peer;
47 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
48 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
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.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRibBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
84 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
85 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
86 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
87 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
88 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91
92 @ThreadSafe
93 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
94     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
95     private static final Update EOR = new UpdateBuilder().build();
96     private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
97
98     /*
99      * FIXME: performance: this needs to be turned into a Peer->offset map.
100      *        The offset is used to locate a the per-peer state entry in the
101      *        RIB tables.
102      *
103      *        For the first release, that map is updated whenever configuration
104      *        changes and remains constant on peer flaps. On re-configuration
105      *        a resize task is scheduled, so large tables may take some time
106      *        before they continue reacting to updates.
107      *
108      *        For subsequent releases, if we make the reformat process concurrent,
109      *        we can trigger reformats when Graceful Restart Time expires for a
110      *        particular peer.
111      */
112     private final ConcurrentMap<Peer, AdjRIBsOut> ribOuts = new ConcurrentHashMap<>();
113     private final ReconnectStrategyFactory tcpStrategyFactory;
114     private final ReconnectStrategyFactory sessionStrategyFactory;
115
116     /**
117      * BGP Best Path selection comparator for ingress best path selection.
118      */
119     private final BGPObjectComparator comparator;
120     private final BGPDispatcher dispatcher;
121     private final BindingTransactionChain chain;
122     private final AsNumber localAs;
123     private final Ipv4Address bgpIdentifier;
124     private final Ipv4Address clusterId;
125     private final Set<BgpTableType> localTables;
126     private final RIBTables tables;
127     private final BlockingQueue<Peer> peers;
128     private final DataBroker dataBroker;
129     private final DOMDataBroker domDataBroker;
130     private final RIBExtensionConsumerContext extensions;
131
132     private final RIBSupportContextRegistryImpl ribContextRegistry;
133
134     private final Runnable scheduler = new Runnable() {
135         @Override
136         public void run() {
137             try {
138                 final Peer peer = RIBImpl.this.peers.take();
139                 LOG.debug("Advertizing loc-rib to new peer {}.", peer);
140                 for (final BgpTableType key : RIBImpl.this.localTables) {
141
142                     synchronized (RIBImpl.this) {
143                         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(RIBImpl.this.ribOuts, RIBImpl.this.comparator, RIBImpl.this.chain.newWriteOnlyTransaction());
144                         final AbstractAdjRIBs<?, ?, ?> adj = (AbstractAdjRIBs<?, ?, ?>) RIBImpl.this.tables.get(new TablesKey(key.getAfi(), key.getSafi()));
145                         adj.addAllEntries(trans);
146                         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
147                             @Override
148                             public void onSuccess(final Void result) {
149                                 LOG.trace("Advertizing {} to peer {} committed successfully", key.getAfi(), peer);
150                             }
151                             @Override
152                             public void onFailure(final Throwable t) {
153                                 LOG.error("Failed to update peer {} with RIB {}", peer, t);
154                             }
155                         });
156                     }
157                 }
158             } catch (final InterruptedException e) {
159                 LOG.info("Scheduler thread was interrupted.", e);
160             }
161         }
162     };
163
164     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
165         final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
166         final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, GeneratedClassLoadingStrategy classStrategy) {
167         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
168         this.chain = dps.createTransactionChain(this);
169         this.localAs = Preconditions.checkNotNull(localAs);
170         this.comparator = new BGPObjectComparator(localAs);
171         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
172         this.clusterId = clusterId == null ? localBgpId : clusterId;
173         this.dispatcher = Preconditions.checkNotNull(dispatcher);
174         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
175         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
176         this.localTables = ImmutableSet.copyOf(localTables);
177         this.tables = new RIBTables(extensions);
178         this.peers = new LinkedBlockingQueue<>();
179         this.dataBroker = dps;
180         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
181         this.extensions = Preconditions.checkNotNull(extensions);
182         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions,codecFactory, classStrategy);
183
184         LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier());
185
186         final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
187
188         // put empty BgpRib if not exists
189         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(),
190             new RibBuilder().setKey(new RibKey(ribId)).setPeer(Collections.<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer> emptyList()).setId(ribId).setLocRib(
191             new LocRibBuilder().setTables(Collections.<Tables> emptyList()).build()).build(), true);
192
193         for (final BgpTableType t : localTables) {
194             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
195             if (this.tables.create(trans, this, key) == null) {
196                 LOG.debug("Did not create local table for unhandled table type {}", t);
197             }
198         }
199
200         Futures.addCallback(trans.submit(), new FutureCallback<Void>() {
201             @Override
202             public void onSuccess(final Void result) {
203                 LOG.trace("Change committed successfully");
204             }
205
206             @Override
207             public void onFailure(final Throwable t) {
208                 LOG.error("Failed to initiate RIB {}", getInstanceIdentifier(), t);
209             }
210         });
211     }
212
213     synchronized void initTables(final byte[] remoteBgpId) {
214     }
215
216     @Override
217     public synchronized void updateTables(final Peer peer, final Update message) {
218         final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
219
220         if (!EOR.equals(message)) {
221             final WithdrawnRoutes wr = message.getWithdrawnRoutes();
222             if (wr != null) {
223                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
224                 if (ari != null) {
225                     /*
226                      * create MPUnreach for the routes to be handled in the same way as linkstate routes
227                      */
228                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
229                     for (final Ipv4Prefix p : wr.getWithdrawnRoutes()) {
230                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
231                     }
232                     ari.removeRoutes(
233                         trans,
234                         peer,
235                         new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes(
236                             new WithdrawnRoutesBuilder().setDestinationType(
237                                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
238                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build());
239                 } else {
240                     LOG.debug("Not removing objects from unhandled IPv4 Unicast");
241                 }
242             }
243
244             final PathAttributes attrs = message.getPathAttributes();
245             if (attrs != null) {
246                 final PathAttributes2 mpu = attrs.getAugmentation(PathAttributes2.class);
247                 if (mpu != null) {
248                     final MpUnreachNlri nlri = mpu.getMpUnreachNlri();
249                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
250                     // EOR messages do not contain withdrawn routes
251                     if (nlri.getWithdrawnRoutes() != null) {
252                         if (ari != null) {
253                             ari.removeRoutes(trans, peer, nlri);
254                         } else {
255                             LOG.debug("Not removing objects from unhandled NLRI {}", nlri);
256                         }
257                     } else {
258                         ari.markUptodate(trans, peer);
259                     }
260                 }
261             }
262
263             final Nlri ar = message.getNlri();
264             if (ar != null) {
265                 final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
266                 if (ari != null) {
267                     /*
268                      * create MPReach for the routes to be handled in the same way as linkstate routes
269                      */
270                     final List<Ipv4Prefixes> prefixes = new ArrayList<>();
271                     for (final Ipv4Prefix p : ar.getNlri()) {
272                         prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
273                     }
274                     final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
275                         UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
276                             new AdvertizedRoutesBuilder().setDestinationType(
277                                 new DestinationIpv4CaseBuilder().setDestinationIpv4(
278                                     new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
279                     if (attrs != null) {
280                         b.setCNextHop(attrs.getCNextHop());
281                     }
282
283                     ari.addRoutes(trans, peer, b.build(), attrs);
284                 } else {
285                     LOG.debug("Not adding objects from unhandled IPv4 Unicast");
286                 }
287             }
288
289             if (attrs != null) {
290                 final PathAttributes1 mpr = attrs.getAugmentation(PathAttributes1.class);
291                 if (mpr != null) {
292                     final MpReachNlri nlri = mpr.getMpReachNlri();
293
294                     final AdjRIBsIn<?, ?> ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi()));
295                     if (ari != null) {
296                         if (message.equals(ari.endOfRib())) {
297                             ari.markUptodate(trans, peer);
298                         } else {
299                             ari.addRoutes(trans, peer, nlri, attrs);
300                         }
301                     } else {
302                         LOG.debug("Not adding objects from unhandled NLRI {}", nlri);
303                     }
304                 }
305             }
306         } else {
307             final AdjRIBsIn<?, ?> ari = this.tables.get(IPV4_UNICAST_TABLE);
308             if (ari != null) {
309                 ari.markUptodate(trans, peer);
310             } else {
311                 LOG.debug("End-of-RIB for IPv4 Unicast ignored");
312             }
313         }
314
315         Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
316             @Override
317             public void onSuccess(final Void result) {
318                 LOG.debug("RIB modification successfully committed.");
319             }
320
321             @Override
322             public void onFailure(final Throwable t) {
323                 LOG.error("Failed to commit RIB modification", t);
324             }
325         });
326     }
327
328     @Override
329     public synchronized void clearTable(final Peer peer, final TablesKey key) {
330         final AdjRIBsIn<?, ?> ari = this.tables.get(key);
331         if (ari != null) {
332             final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction());
333             ari.clear(trans, peer);
334
335             Futures.addCallback(trans.commit(), new FutureCallback<Void>() {
336                 @Override
337                 public void onSuccess(final Void result) {
338                     LOG.trace("Table {} cleared successfully", key);
339                 }
340
341                 @Override
342                 public void onFailure(final Throwable t) {
343                     LOG.error("Failed to clear table {}", key, t);
344                 }
345             });
346         }
347     }
348
349     @Override
350     public String toString() {
351         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
352     }
353
354     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
355         return toStringHelper;
356     }
357
358     @SuppressWarnings("unchecked")
359     protected <K, V extends Route> AdjRIBsIn<K, V> getTable(final TablesKey key) {
360         return (AdjRIBsIn<K, V>) this.tables.get(key);
361     }
362
363     @Override
364     public synchronized void close() throws InterruptedException, ExecutionException {
365         final WriteTransaction t = this.chain.newWriteOnlyTransaction();
366         t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
367         t.submit().get();
368         this.chain.close();
369     }
370
371     @Override
372     public AsNumber getLocalAs() {
373         return this.localAs;
374     }
375
376     @Override
377     public Ipv4Address getBgpIdentifier() {
378         return this.bgpIdentifier;
379     }
380
381     @Override
382     public Set<? extends BgpTableType> getLocalTables() {
383         return this.localTables;
384     }
385
386     @Override
387     public ReconnectStrategyFactory getTcpStrategyFactory() {
388         return this.tcpStrategyFactory;
389     }
390
391     @Override
392     public ReconnectStrategyFactory getSessionStrategyFactory() {
393         return this.sessionStrategyFactory;
394     }
395
396     @Override
397     public BGPDispatcher getDispatcher() {
398         return this.dispatcher;
399     }
400
401     @Override
402     public void initTable(final Peer bgpPeer, final TablesKey key) {
403         // FIXME: BUG-196: support graceful restart
404     }
405
406     @Override
407     public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) {
408         final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) {
409             @Override
410             protected void removeRegistration() {
411                 RIBImpl.this.ribOuts.remove(peer, aro);
412             }
413         };
414
415         this.ribOuts.put(peer, aro);
416         LOG.debug("Registering this peer {} to RIB-Out {}", peer, this.ribOuts);
417         try {
418             this.peers.put(peer);
419             new Thread(this.scheduler).start();
420         } catch (final InterruptedException e) {
421             //
422         }
423         return reg;
424     }
425
426     @Override
427     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
428         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
429     }
430
431     @Override
432     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
433         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
434     }
435
436     @Override
437     public long getRoutesCount(final TablesKey key) {
438         try {
439             final Optional<Tables> tableMaybe = this.dataBroker.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL,
440                     getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
441             if (tableMaybe.isPresent()) {
442                 final Tables table = tableMaybe.get();
443                 if (table.getRoutes() instanceof Ipv4RoutesCase) {
444                     final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
445                     if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
446                         return routesCase.getIpv4Routes().getIpv4Route().size();
447                     }
448                 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
449                     final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
450                     if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
451                         return routesCase.getIpv6Routes().getIpv6Route().size();
452                     }
453                 }
454             }
455         } catch (final ReadFailedException e) {
456             //no-op
457         }
458         return 0;
459     }
460
461     @Override
462     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
463         return this.domDataBroker.createTransactionChain(listener);
464     }
465
466     @Override
467     public RIBExtensionConsumerContext getRibExtensions() {
468         return this.extensions;
469     }
470
471     @Override
472     public RIBSupportContextRegistry getRibSupportContext() {
473         return this.ribContextRegistry;
474     }
475
476     @Override
477     public void onGlobalContextUpdated(final SchemaContext context) {
478         this.ribContextRegistry.onSchemaContextUpdated(context);
479     }
480 }