X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=bgp%2Frib-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fprotocol%2Fbgp%2Frib%2Fimpl%2FBGPPeer.java;h=6a0996bd7eb07b0b5fc0b19ff6b29a7076de01c9;hb=38165f9ef743f7c8df7a036349850f31fd89bc32;hp=e46a735512a273f1611ad0d77e94c6b54cff5965;hpb=2db6622d02d1e19621fd35342da64c0a6663cdc3;p=bgpcep.git diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java index e46a735512..6a0996bd7e 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java @@ -8,9 +8,10 @@ package org.opendaylight.protocol.bgp.rib.impl; import static java.util.Objects.requireNonNull; +import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBOUT_NID; +import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID; import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; import com.google.common.base.Stopwatch; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -18,7 +19,6 @@ import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -import com.google.common.net.InetAddresses; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -29,18 +29,19 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.checkerframework.checker.lock.qual.GuardedBy; import org.checkerframework.checker.lock.qual.Holding; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.api.RpcProviderService; -import org.opendaylight.mdsal.binding.api.Transaction; -import org.opendaylight.mdsal.binding.api.TransactionChain; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction; import org.opendaylight.mdsal.dom.api.DOMTransactionChain; +import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener; import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer; import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.BGPError; @@ -62,46 +63,42 @@ import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState; import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState; import org.opendaylight.protocol.util.Ipv4Util; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.DestinationIpv4Builder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4Prefixes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.Update; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.open.message.BgpParameters; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.update.message.Nlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.Update; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.open.message.BgpParameters; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.update.message.Nlri; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpAddPathTableType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.RouteRefresh; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.GracefulRestartCapability; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.BgpPeerRpcService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.PeerKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibOut; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.AddressFamily; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.Ipv4AddressFamily; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.RouteTarget; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.SubsequentAddressFamily; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.UnicastSubsequentAddressFamily; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.ClusterIdentifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv4AddressFamily; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteTarget; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.UnicastSubsequentAddressFamily; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.opendaylight.yangtools.yang.binding.Notification; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -111,29 +108,34 @@ import org.slf4j.LoggerFactory; */ public class BGPPeer extends AbstractPeer implements BGPSessionListener { private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class); - private static final TablesKey IPV4_UCAST_TABLE_KEY = new TablesKey(Ipv4AddressFamily.class, - UnicastSubsequentAddressFamily.class); + private static final TablesKey IPV4_UCAST_TABLE_KEY = + new TablesKey(Ipv4AddressFamily.VALUE, UnicastSubsequentAddressFamily.VALUE); - private ImmutableSet tables = ImmutableSet.of(); private final RIB rib; + + // FIXME: Alright, this right here is a ton of state which has intertwined initialization and dependencies Split + // these out into separate behavior objects. This also has relationship with state in AbstractPeer -- which + // hints at an obvious layer of indirection. Yeah, yeah, we can always add one of those, but the point + // is that this class is a mutable meeting point, whereas the behaviour has captured invariants. + private final LoadingCache tablesIId = + CacheBuilder.newBuilder().build(new CacheLoader() { + @Override + public YangInstanceIdentifier load(final NodeIdentifierWithPredicates key) { + return peerRibOutIId.node(TABLES_NID).node(key).toOptimized(); + } + }); + + private ImmutableSet tables = ImmutableSet.of(); private final Map adjRibOutListenerSet = new HashMap<>(); private final List rtMemberships = new ArrayList<>(); private final RpcProviderService rpcRegistry; private final BGPTableTypeRegistryConsumer tableTypeRegistry; private final BgpPeer bgpPeer; - private InstanceIdentifier peerRibOutIId; - private KeyedInstanceIdentifier peerIId; + + // FIXME: This should be a constant co-located with ApplicationPeer.peerId + private YangInstanceIdentifier peerRibOutIId; @GuardedBy("this") private Registration trackerRegistration; - private final LoadingCache> tablesIId - = CacheBuilder.newBuilder() - .build(new CacheLoader>() { - @Override - public KeyedInstanceIdentifier load(final TablesKey tablesKey) { - return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey); - } - }); @GuardedBy("this") private BGPSession currentSession; @@ -142,8 +144,10 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { @GuardedBy("this") private EffectiveRibInWriter effRibInWriter; private ObjectRegistration rpcRegistration; - private Map addPathTableMaps = Collections.emptyMap(); + private ImmutableMap addPathTableMaps = ImmutableMap.of(); + // FIXME: This should be a constant co-located with ApplicationPeer.peerId private YangInstanceIdentifier peerPath; + // FIXME: This is for supportsTable() -- a trivial behavior thing, where 'peer-down' type states always return false private boolean sessionUp; private boolean llgrSupport; private Stopwatch peerRestartStopwatch; @@ -152,7 +156,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { public BGPPeer( final BGPTableTypeRegistryConsumer tableTypeRegistry, - final IpAddress neighborAddress, + final IpAddressNoZone neighborAddress, final String peerGroupName, final RIB rib, final PeerRole role, @@ -190,11 +194,14 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { final List prefixes = message.getNlri().stream() .map(n -> new Ipv4PrefixesBuilder().setPrefix(n.getPrefix()).setPathId(n.getPathId()).build()) .collect(Collectors.toList()); - final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi( - UnicastSubsequentAddressFamily.class).setAdvertizedRoutes( - new AdvertizedRoutesBuilder().setDestinationType( - new DestinationIpv4CaseBuilder().setDestinationIpv4( - new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()); + final MpReachNlriBuilder b = new MpReachNlriBuilder() + .setAfi(Ipv4AddressFamily.VALUE) + .setSafi(UnicastSubsequentAddressFamily.VALUE) + .setAdvertizedRoutes(new AdvertizedRoutesBuilder() + .setDestinationType(new DestinationIpv4CaseBuilder() + .setDestinationIpv4(new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()) + .build()) + .build()); if (message.getAttributes() != null) { b.setCNextHop(message.getAttributes().getCNextHop()); } @@ -214,57 +221,59 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { Optional nlriAnounced = Optional.empty(); if (isAnyNlriAnnounced) { - nlriAnounced = message.getNlri().stream().filter(n -> Objects.equal(n.getPrefix(), w.getPrefix()) - && Objects.equal(n.getPathId(), w.getPathId())) + nlriAnounced = message.getNlri().stream().filter(n -> Objects.equals(n.getPrefix(), w.getPrefix()) + && Objects.equals(n.getPathId(), w.getPathId())) .findAny(); } if (!nlriAnounced.isPresent()) { prefixes.add(new Ipv4PrefixesBuilder().setPrefix(w.getPrefix()).setPathId(w.getPathId()).build()); } }); - return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class) + return new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.VALUE).setSafi(UnicastSubsequentAddressFamily.VALUE) .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1 .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.unreach.nlri .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4( - new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build(); + new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build(); } - private static Map mapTableTypesFamilies(final List addPathTablesType) { - return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(), - af.getSafi()), BgpAddPathTableType::getSendReceive))); + private static ImmutableMap mapTableTypesFamilies( + final List addPathTablesType) { + return addPathTablesType.stream().collect(ImmutableMap.toImmutableMap( + af -> new TablesKey(af.getAfi(), af.getSafi()), BgpAddPathTableType::getSendReceive)); } public synchronized void instantiateServiceInstance() { - this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this); + createDomChain(); + ribWriter = AdjRibInWriter.create(rib.getYangRibId(), getRole(), this); setActive(true); } @Override public synchronized FluentFuture close() { - final FluentFuture future = releaseConnection(); + final FluentFuture future = releaseConnection(true); closeDomChain(); setActive(false); return future; } @Override - public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException { - if (msg instanceof Update) { - onUpdateMessage((Update) msg); - } else if (msg instanceof RouteRefresh) { - onRouteRefreshMessage((RouteRefresh) msg); + public void onMessage(final BGPSession session, final Notification msg) throws BGPDocumentedException { + if (msg instanceof Update update) { + onUpdateMessage(update); + } else if (msg instanceof RouteRefresh routeRefresh) { + onRouteRefreshMessage(routeRefresh); } else { LOG.info("Ignoring unhandled message class {}", msg.getClass()); } } private void onRouteRefreshMessage(final RouteRefresh message) { - final Class rrAfi = message.getAfi(); - final Class rrSafi = message.getSafi(); + final var rrAfi = message.getAfi(); + final var rrSafi = message.getSafi(); final TablesKey key = new TablesKey(rrAfi, rrSafi); synchronized (this) { - final AdjRibOutListener listener = this.adjRibOutListenerSet.remove(key); + final AdjRibOutListener listener = adjRibOutListenerSet.remove(key); if (listener != null) { listener.close(); createAdjRibOutListener(key, listener.isMpSupported()); @@ -282,7 +291,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException { if (MessageUtil.isAnyNlriPresent(message)) { final Attributes attrs = message.getAttributes(); - if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) { + if (getRole() == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) { throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF", BGPError.WELL_KNOWN_ATTR_MISSING, new byte[]{LocalPreferenceAttributeParser.TYPE}); @@ -309,7 +318,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { mpReach = MessageUtil.getMpReachNlri(attrs); } if (mpReach != null) { - this.ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach)); + ribWriter.updateRoutes(mpReach, nextHopToAttribute(attrs, mpReach)); } final MpUnreachNlri mpUnreach; if (message.getWithdrawnRoutes() != null) { @@ -321,15 +330,15 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { if (mpUnreach != null) { if (endOfRib) { final TablesKey tablesKey = new TablesKey(mpUnreach.getAfi(), mpUnreach.getSafi()); - this.ribWriter.removeStaleRoutes(tablesKey); - this.missingEOT.remove(tablesKey); + ribWriter.removeStaleRoutes(tablesKey); + missingEOT.remove(tablesKey); handleGracefulEndOfRib(); } else { - this.ribWriter.removeRoutes(mpUnreach); + ribWriter.removeRoutes(mpUnreach); } } else if (endOfRib) { - this.ribWriter.removeStaleRoutes(IPV4_UCAST_TABLE_KEY); - this.missingEOT.remove(IPV4_UCAST_TABLE_KEY); + ribWriter.removeStaleRoutes(IPV4_UCAST_TABLE_KEY); + missingEOT.remove(IPV4_UCAST_TABLE_KEY); handleGracefulEndOfRib(); } } @@ -337,10 +346,10 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { @Holding("this") private void handleGracefulEndOfRib() { if (isLocalRestarting()) { - if (this.missingEOT.isEmpty()) { + if (missingEOT.isEmpty()) { createEffRibInWriter(); - this.effRibInWriter.init(); - registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter); + effRibInWriter.init(); + registerPrefixesCounters(effRibInWriter, effRibInWriter); for (final TablesKey key : getAfiSafisAdvertized()) { createAdjRibOutListener(key, true); } @@ -352,76 +361,89 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { @Override public synchronized void onSessionUp(final BGPSession session) { - this.currentSession = session; - this.sessionUp = true; - this.bindingChain = this.rib.createPeerChain(this); - if (this.currentSession instanceof BGPSessionStateProvider) { - ((BGPSessionStateProvider) this.currentSession).registerMessagesCounter(this); + currentSession = session; + sessionUp = true; + + ribOutChain = rib.createPeerDOMChain(new DOMTransactionChainListener() { + @Override + public void onTransactionChainSuccessful(final DOMTransactionChain chain) { + LOG.debug("RibOut transaction chain {} successful.", chain); + } + + @Override + public void onTransactionChainFailed(final DOMTransactionChain chain, + final DOMDataTreeTransaction transaction, final Throwable cause) { + onRibOutChainFailed(cause); + } + }); + + if (currentSession instanceof BGPSessionStateProvider stateProvider) { + stateProvider.registerMessagesCounter(this); } final GracefulRestartCapability advertisedGracefulRestartCapability = session.getAdvertisedGracefulRestartCapability(); - final List advertisedTables = - advertisedGracefulRestartCapability.getTables(); - final List advertisedLLTables = - session.getAdvertisedLlGracefulRestartCapability().getTables(); + final var advertisedTables = advertisedGracefulRestartCapability.getTables(); + final var advertisedLLTables = session.getAdvertisedLlGracefulRestartCapability().getTables(); final List addPathTablesType = session.getAdvertisedAddPathTableTypes(); final Set advertizedTableTypes = session.getAdvertisedTableTypes(); - LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name, + LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", getName(), advertizedTableTypes, addPathTablesType); final Set setTables = advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi())) .collect(Collectors.toSet()); - this.tables = ImmutableSet.copyOf(setTables); + tables = ImmutableSet.copyOf(setTables); - this.addPathTableMaps = mapTableTypesFamilies(addPathTablesType); + addPathTableMaps = mapTableTypesFamilies(addPathTablesType); final boolean restartingLocally = isLocalRestarting(); - + if (!restartingLocally) { + addBgp4Support(); + } if (!isRestartingGracefully()) { - this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress(); - this.peerId = RouterIds.createPeerId(session.getBgpId()); - this.peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns - .yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId)); - this.peerPath = createPeerPath(); - this.peerRibOutIId = peerIId.child(AdjRibOut.class); - this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this); + peerId = RouterIds.createPeerId(session.getBgpId()); + + final KeyedInstanceIdentifier peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen + .v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, + new PeerKey(peerId)); + peerPath = createPeerPath(peerId); + peerRibOutIId = peerPath.node(ADJRIBOUT_NID); + trackerRegistration = rib.getPeerTracker().registerPeer(this); createEffRibInWriter(); - registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter); + registerPrefixesCounters(effRibInWriter, effRibInWriter); - this.effRibInWriter.init(); - this.ribWriter = this.ribWriter.transform(this.peerId, this.peerPath, this.rib.getRibSupportContext(), - this.tables, this.addPathTableMaps); + effRibInWriter.init(); + ribWriter = ribWriter.transform(peerId, peerPath, rib.getRibSupportContext(), + tables, addPathTableMaps); - if (this.rpcRegistry != null) { - this.rpcRegistration = this.rpcRegistry.registerRpcImplementation(BgpPeerRpcService.class, - new BgpPeerRpc(this, session, this.tables), ImmutableSet.of(this.rib.getInstanceIdentifier().child( + if (rpcRegistry != null) { + rpcRegistration = rpcRegistry.registerRpcImplementation(BgpPeerRpcService.class, + new BgpPeerRpc(this, session, tables), ImmutableSet.of(rib.getInstanceIdentifier().child( org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib - .Peer.class, new PeerKey(this.peerId)))); + .Peer.class, new PeerKey(peerId)))); } } else { final Set forwardingTables; if (advertisedTables == null) { forwardingTables = Collections.emptySet(); } else { - forwardingTables = advertisedTables.stream() + forwardingTables = advertisedTables.values().stream() .filter(table -> table.getAfiFlags() != null) - .filter(table -> table.getAfiFlags().isForwardingState()) + .filter(table -> table.getAfiFlags().getForwardingState()) .map(table -> new TablesKey(table.getAfi(), table.getSafi())) .collect(Collectors.toSet()); } - this.ribWriter.clearTables(Sets.difference(this.tables, forwardingTables)); + ribWriter.clearTables(Sets.difference(tables, forwardingTables)); if (restartingLocally) { - this.effRibInWriter.close(); - this.peerRestartStopwatch = Stopwatch.createStarted(); + effRibInWriter.close(); + peerRestartStopwatch = Stopwatch.createStarted(); handleSelectionReferralTimer(); - this.missingEOT.addAll(this.tables); + missingEOT.addAll(tables); } } if (advertisedTables == null || advertisedTables.isEmpty()) { setAdvertizedGracefulRestartTableTypes(Collections.emptyList()); } else { - setAdvertizedGracefulRestartTableTypes(advertisedTables.stream() + setAdvertizedGracefulRestartTableTypes(advertisedTables.values().stream() .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList())); } setAfiSafiGracefulRestartState(advertisedGracefulRestartCapability.getRestartTime().toJava(), false, @@ -430,10 +452,9 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { final Map llTablesReceived; if (advertisedLLTables != null) { llTablesReceived = new HashMap<>(); - for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp - .capabilities.ll.graceful.restart.capability.Tables table : advertisedLLTables) { + for (var table : advertisedLLTables.values()) { llTablesReceived.put(new TablesKey(table.getAfi(), table.getSafi()), - table.getLongLivedStaleTime().intValue()); + table.getLongLivedStaleTime().getValue().intValue()); } } else { llTablesReceived = Collections.emptyMap(); @@ -449,16 +470,18 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { } if (!restartingLocally) { - addBgp4Support(); + if (!setTables.contains(IPV4_UCAST_TABLE_KEY)) { + createAdjRibOutListener(IPV4_UCAST_TABLE_KEY, false); + } for (final TablesKey key : getAfiSafisAdvertized()) { createAdjRibOutListener(key, true); } } // SpotBugs does not grok Optional.ifPresent() and thinks we are using unsynchronized access - final Optional errorHandling = this.bgpPeer.getErrorHandling(); + final Optional errorHandling = bgpPeer.getErrorHandling(); if (errorHandling.isPresent()) { - this.currentSession.addDecoderConstraint(RevisedErrorHandlingSupport.class, errorHandling.get()); + currentSession.addDecoderConstraint(RevisedErrorHandlingSupport.class, errorHandling.get()); } } @@ -467,35 +490,34 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { } private synchronized void createEffRibInWriter() { - this.effRibInWriter = new EffectiveRibInWriter(this, this.rib, - this.rib.createPeerDOMChain(this), - this.peerPath, this.tables, this.tableTypeRegistry, - this.rtMemberships, - this.rtCache); + effRibInWriter = new EffectiveRibInWriter(this, rib, + rib.createPeerDOMChain(this), + peerPath, tables, tableTypeRegistry, + rtMemberships, + rtCache); } //try to add a support for old-school BGP-4, if peer did not advertise IPv4-Unicast MP capability @Holding("this") private void addBgp4Support() { - if (!this.tables.contains(IPV4_UCAST_TABLE_KEY)) { - final HashSet newSet = new HashSet<>(this.tables); + if (!tables.contains(IPV4_UCAST_TABLE_KEY)) { + final HashSet newSet = new HashSet<>(tables); newSet.add(IPV4_UCAST_TABLE_KEY); - this.tables = ImmutableSet.copyOf(newSet); - createAdjRibOutListener(IPV4_UCAST_TABLE_KEY, false); + tables = ImmutableSet.copyOf(newSet); } } @Holding("this") private void createAdjRibOutListener(final TablesKey key, final boolean mpSupport) { - final RIBSupport ribSupport = this.rib.getRibSupportContext().getRIBSupport(key); + final RIBSupport ribSupport = rib.getRibSupportContext().getRIBSupport(key); // not particularly nice - if (ribSupport != null && this.currentSession instanceof BGPSessionImpl) { - final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.currentSession).getLimiter(); - final AdjRibOutListener adjRibOut = AdjRibOutListener.create(this.peerId, key, - this.rib.getYangRibId(), this.rib.getCodecsRegistry(), ribSupport, - this.rib.getService(), limiter, mpSupport); - this.adjRibOutListenerSet.put(key, adjRibOut); + if (ribSupport != null && currentSession instanceof BGPSessionImpl bgpSession) { + final ChannelOutputLimiter limiter = bgpSession.getLimiter(); + final AdjRibOutListener adjRibOut = AdjRibOutListener.create(peerId, key, + rib.getYangRibId(), rib.getCodecsRegistry(), ribSupport, + rib.getService(), limiter, mpSupport); + adjRibOutListenerSet.put(key, adjRibOut); registerPrefixesSentCounter(key, adjRibOut); } } @@ -503,43 +525,56 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { @Override public synchronized void onSessionDown(final BGPSession session, final Exception exc) { if (exc.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) { - LOG.info("Session with peer {} went down", this.name); + LOG.info("Session with peer {} went down", getName()); } else { - LOG.info("Session with peer {} went down", this.name, exc); + LOG.info("Session with peer {} went down", getName(), exc); } releaseConnectionGracefully(); } @Override public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) { - LOG.info("Session with peer {} terminated: {}", this.name, cause); + LOG.info("Session with peer {} terminated: {}", getName(), cause); releaseConnectionGracefully(); } @Override public String toString() { - return MoreObjects.toStringHelper(this).add("name", this.name).add("tables", this.tables).toString(); + return MoreObjects.toStringHelper(this).add("name", getName()).add("tables", tables).toString(); } @Override public synchronized FluentFuture releaseConnection() { + return releaseConnection(true); + } + + /** + * On transaction chain failure, we don't want to wait for future. + * + * @param isWaitForSubmitted if true, wait for submitted future before closing binding chain. if false, don't wait. + */ + @Holding("this") + private @NonNull FluentFuture releaseConnection(final boolean isWaitForSubmitted) { LOG.info("Closing session with peer"); - this.sessionUp = false; - this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close); - this.adjRibOutListenerSet.clear(); + sessionUp = false; + adjRibOutListenerSet.values().forEach(AdjRibOutListener::close); + adjRibOutListenerSet.clear(); final FluentFuture future; - if (!isRestartingGracefully()) { - future = terminateConnection(); - } else { + // FIXME: this is a typical example of something which should be handled by a behavior into which we have + // transitioned way before this method is called. This really begs to be an abstract base class with + // a 'clearTables' or similar callout + if (isRestartingGracefully()) { final Set gracefulTables = getGracefulTables(); - this.ribWriter.storeStaleRoutes(gracefulTables); - future = this.ribWriter.clearTables(Sets.difference(this.tables, gracefulTables)); + ribWriter.storeStaleRoutes(gracefulTables); + future = ribWriter.clearTables(Sets.difference(tables, gracefulTables)); if (isPeerRestarting()) { - this.peerRestartStopwatch = Stopwatch.createStarted(); + peerRestartStopwatch = Stopwatch.createStarted(); handleRestartTimer(); } + } else { + future = terminateConnection(); } - releaseBindingChain(); + releaseRibOutChain(isWaitForSubmitted); closeSession(); return future; @@ -548,22 +583,22 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { @Holding("this") @SuppressWarnings("checkstyle:illegalCatch") private void closeSession() { - if (this.currentSession != null) { + if (currentSession != null) { try { if (isRestartingGracefully()) { - this.currentSession.closeWithoutMessage(); + currentSession.closeWithoutMessage(); } else { - this.currentSession.close(); + currentSession.close(); } } catch (final Exception e) { LOG.warn("Error closing session with peer", e); } - this.currentSession = null; + currentSession = null; } } private Set getGracefulTables() { - return this.tables.stream() + return tables.stream() .filter(this::isGracefulRestartReceived) .filter(this::isGracefulRestartAdvertized) .collect(Collectors.toSet()); @@ -571,21 +606,21 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { private synchronized FluentFuture terminateConnection() { final FluentFuture future; - if (this.trackerRegistration != null) { - this.trackerRegistration.close(); - this.trackerRegistration = null; + if (trackerRegistration != null) { + trackerRegistration.close(); + trackerRegistration = null; } - if (this.rpcRegistration != null) { - this.rpcRegistration.close(); + if (rpcRegistration != null) { + rpcRegistration.close(); } - this.ribWriter.releaseChain(); + ribWriter.releaseChain(); - if (this.effRibInWriter != null) { - this.effRibInWriter.close(); + if (effRibInWriter != null) { + effRibInWriter.close(); } - this.tables = ImmutableSet.of(); - this.addPathTableMaps = Collections.emptyMap(); - future = removePeer(this.peerPath); + tables = ImmutableSet.of(); + addPathTableMaps = ImmutableMap.of(); + future = removePeer(peerPath); resetState(); return future; @@ -600,10 +635,10 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { } final long peerRestartTimeNanos = TimeUnit.SECONDS.toNanos(getPeerRestartTime()); - final long elapsedNanos = this.peerRestartStopwatch.elapsed(TimeUnit.NANOSECONDS); + final long elapsedNanos = peerRestartStopwatch.elapsed(TimeUnit.NANOSECONDS); if (elapsedNanos >= peerRestartTimeNanos) { setAfiSafiGracefulRestartState(0, false, false); - onSessionTerminated(this.currentSession, new BGPTerminationReason(BGPError.HOLD_TIMER_EXPIRED)); + onSessionTerminated(currentSession, new BGPTerminationReason(BGPError.HOLD_TIMER_EXPIRED)); } currentSession.schedule(this::handleRestartTimer, peerRestartTimeNanos - elapsedNanos, TimeUnit.NANOSECONDS); @@ -614,115 +649,114 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { return; } - final long referalTimerNanos = TimeUnit.SECONDS.toNanos(this.currentSelectionDeferralTimerSeconds); - final long elapsedNanos = this.peerRestartStopwatch.elapsed(TimeUnit.NANOSECONDS); + final long referalTimerNanos = TimeUnit.SECONDS.toNanos(currentSelectionDeferralTimerSeconds); + final long elapsedNanos = peerRestartStopwatch.elapsed(TimeUnit.NANOSECONDS); if (elapsedNanos >= referalTimerNanos) { - this.missingEOT.clear(); + missingEOT.clear(); handleGracefulEndOfRib(); } currentSession.schedule(this::handleSelectionReferralTimer, referalTimerNanos - elapsedNanos, TimeUnit.NANOSECONDS); } + @Holding("this") private void releaseConnectionGracefully() { if (getPeerRestartTime() > 0) { setRestartingState(); } - releaseConnection(); + releaseConnection(true); } @SuppressFBWarnings("IS2_INCONSISTENT_SYNC") @Override public SendReceive getSupportedAddPathTables(final TablesKey tableKey) { - return this.addPathTableMaps.get(tableKey); + return addPathTableMaps.get(tableKey); } @Override public boolean supportsTable(final TablesKey tableKey) { - return this.sessionUp && getAfiSafisAdvertized().contains(tableKey); + return sessionUp && getAfiSafisAdvertized().contains(tableKey) && tables.contains(tableKey); } @Override - public KeyedInstanceIdentifier getRibOutIId(final TablesKey tablesKey) { - return this.tablesIId.getUnchecked(tablesKey); + public YangInstanceIdentifier getRibOutIId(final NodeIdentifierWithPredicates tablekey) { + return tablesIId.getUnchecked(tablekey); } @Override public synchronized void onTransactionChainFailed(final DOMTransactionChain chain, final DOMDataTreeTransaction transaction, final Throwable cause) { LOG.error("Transaction domChain failed.", cause); - releaseConnection(); + releaseConnection(true); } - @Override - public synchronized void onTransactionChainFailed(final TransactionChain chain, final Transaction transaction, - final Throwable cause) { - LOG.error("Transaction domChain failed.", cause); - releaseConnection(); + private synchronized void onRibOutChainFailed(final Throwable cause) { + LOG.error("RibOut transaction chain failed.", cause); + releaseConnection(false); } @Override public synchronized void markUptodate(final TablesKey tablesKey) { - this.ribWriter.markTableUptodate(tablesKey); + ribWriter.markTableUptodate(tablesKey); } @Override public synchronized BGPSessionState getBGPSessionState() { - if (this.currentSession instanceof BGPSessionStateProvider) { - return ((BGPSessionStateProvider) this.currentSession).getBGPSessionState(); + if (currentSession instanceof BGPSessionStateProvider stateProvider) { + return stateProvider.getBGPSessionState(); } return null; } @Override public synchronized BGPTimersState getBGPTimersState() { - if (this.currentSession instanceof BGPSessionStateProvider) { - return ((BGPSessionStateProvider) this.currentSession).getBGPTimersState(); + if (currentSession instanceof BGPSessionStateProvider stateProvider) { + return stateProvider.getBGPTimersState(); } return null; } @Override public synchronized BGPTransportState getBGPTransportState() { - if (this.currentSession instanceof BGPSessionStateProvider) { - return ((BGPSessionStateProvider) this.currentSession).getBGPTransportState(); + if (currentSession instanceof BGPSessionStateProvider stateProvider) { + return stateProvider.getBGPTransportState(); } return null; } @Override public List getMemberships() { - return this.rtMemberships; + return rtMemberships; } @Override public synchronized ListenableFuture restartGracefully(final long selectionDeferralTimerSeconds) { final Set tablesToPreserve = getGracefulTables(); if (tablesToPreserve == null || tablesToPreserve.isEmpty()) { - LOG.info("Peer {} is not capable of graceful restart or have no matching graceful tables.", this.peerId); + LOG.info("Peer {} is not capable of graceful restart or have no matching graceful tables.", peerId); return Futures.immediateFailedFuture(new UnsupportedOperationException( "Peer is not capable of graceful restart")); } setGracefulPreferences(true, tablesToPreserve); - this.currentSelectionDeferralTimerSeconds = selectionDeferralTimerSeconds; + currentSelectionDeferralTimerSeconds = selectionDeferralTimerSeconds; setLocalRestartingState(true); - return releaseConnection(); + return releaseConnection(true); } @Override boolean supportsLLGR() { - return this.llgrSupport; + return llgrSupport; } private synchronized void setGracefulPreferences(final boolean localRestarting, final Set preservedTables) { - final Set gracefulTables = this.tables.stream() + final Set gracefulTables = tables.stream() .filter(this::isGracefulRestartAdvertized) .collect(Collectors.toSet()); final BgpParameters bgpParameters = GracefulRestartUtil.getGracefulBgpParameters( - this.bgpPeer.getBgpFixedCapabilities(), gracefulTables, preservedTables, - this.bgpPeer.getGracefulRestartTimer(), localRestarting, Collections.emptySet()); - final BGPSessionPreferences oldPrefs = this.rib.getDispatcher().getBGPPeerRegistry() + bgpPeer.getBgpFixedCapabilities(), gracefulTables, preservedTables, + bgpPeer.getGracefulRestartTimer(), localRestarting, Collections.emptySet()); + final BGPSessionPreferences oldPrefs = rib.getDispatcher().getBGPPeerRegistry() .getPeerPreferences(getNeighborAddress()); final BGPSessionPreferences newPrefs = new BGPSessionPreferences( oldPrefs.getMyAs(), @@ -731,7 +765,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener { oldPrefs.getExpectedRemoteAs(), Collections.singletonList(bgpParameters), oldPrefs.getMd5Password()); - this.rib.getDispatcher().getBGPPeerRegistry() + rib.getDispatcher().getBGPPeerRegistry() .updatePeerPreferences(getNeighborAddress(), newPrefs); } }