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