default "false";
description
"Specify whether erroneous UPDATE messages for which the
- NLRI can be extracted are reated as though the NLRI is
+ NLRI can be extracted are treated as though the NLRI is
withdrawn - avoiding session reset";
- reference "draft-ietf-idr-error-handling-16";
+ reference "https://tools.ietf.org/html/rfc7606";
}
}
*/
package org.opendaylight.protocol.bgp.parser.spi.pojo;
+import com.google.common.base.MoreObjects;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
public boolean isExternalPeer() {
return externalPeer;
}
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("externalPeer", externalPeer).toString();
+ }
}
import org.opendaylight.protocol.bgp.parser.BGPError;
import org.opendaylight.protocol.bgp.parser.impl.message.update.LocalPreferenceAttributeParser;
import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
import org.opendaylight.protocol.bgp.rib.impl.config.BgpPeer;
import org.opendaylight.protocol.bgp.rib.impl.config.GracefulRestartUtil;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
this.bgpPeer = bgpPeer;
}
- BGPPeer(
- final BGPTableTypeRegistryConsumer tableTypeRegistry,
- final IpAddress neighborAddress,
- final RIB rib,
- final PeerRole role,
- final RpcProviderRegistry rpcRegistry,
- final Set<TablesKey> afiSafisAdvertized,
- final Set<TablesKey> afiSafisGracefulAdvertized) {
- this(tableTypeRegistry, neighborAddress, null, rib, role, null, null, rpcRegistry,
- afiSafisAdvertized, afiSafisGracefulAdvertized, null);
- }
-
-
private static Attributes nextHopToAttribute(final Attributes attrs, final MpReachNlri mpReach) {
if (attrs.getCNextHop() == null && mpReach.getCNextHop() != null) {
final AttributesBuilder attributesBuilder = new AttributesBuilder(attrs);
createAdjRibOutListener(key, true);
}
}
+
+ // SpotBugs does not grok Optional.ifPresent() and thinks we are using unsynchronized access
+ final Optional<RevisedErrorHandlingSupport> errorHandling = this.bgpPeer.getErrorHandling();
+ if (errorHandling.isPresent()) {
+ this.session.addDecoderConstraint(RevisedErrorHandlingSupport.class, errorHandling.get());
+ }
}
private boolean isRestartingGracefully() {
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import java.io.IOException;
import java.nio.channels.NonWritableChannelException;
import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
import org.opendaylight.protocol.bgp.parser.GracefulRestartUtil;
import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupport;
+import org.opendaylight.protocol.bgp.parser.spi.PeerConstraint;
import org.opendaylight.protocol.bgp.parser.spi.pojo.MultiPathSupportImpl;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPMessagesListener;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
this.addPathTypes = addPathCapabilitiesList;
if (!this.addPathTypes.isEmpty()) {
- final ChannelPipeline pipeline = this.channel.pipeline();
- final BGPByteToMessageDecoder decoder = pipeline.get(BGPByteToMessageDecoder.class);
- decoder.addDecoderConstraint(MultiPathSupport.class,
- MultiPathSupportImpl.createParserMultiPathSupport(this.addPathTypes));
+ addDecoderConstraint(MultiPathSupport.class,
+ MultiPathSupportImpl.createParserMultiPathSupport(this.addPathTypes));
}
if (this.holdTimerValue != 0) {
public void registerMessagesCounter(final BGPMessagesListener bgpMessagesListener) {
this.sessionState.registerMessagesCounter(bgpMessagesListener);
}
+
+ @Override
+ public <T extends PeerConstraint> void addDecoderConstraint(final Class<T> constraintClass, final T constraint) {
+ this.channel.pipeline().get(BGPByteToMessageDecoder.class).addDecoderConstraint(constraintClass, constraint);
+ }
}
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
import org.opendaylight.protocol.bgp.parser.BgpExtendedMessageUtil;
import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
private boolean isServiceInstantiated;
private final List<OptionalCapabilities> finalCapabilities;
private final int gracefulRestartTimer;
+ private final RevisedErrorHandlingSupport errorHandling;
private BgpPeerSingletonService(final RIB rib, final Neighbor neighbor, final InstanceIdentifier<Bgp> bgpIid,
final Set<TablesKey> afiSafisAdvertized = OpenConfigMappingUtil
.toTableKey(afisSafis.getAfiSafi(), tableTypeRegistry);
final PeerRole role = OpenConfigMappingUtil.toPeerRole(neighbor, peerGroup);
+
final ClusterIdentifier clusterId = OpenConfigMappingUtil
.getNeighborClusterIdentifier(neighbor.getRouteReflector(), peerGroup);
final int hold = OpenConfigMappingUtil.getHoldTimer(neighbor, peerGroup);
neighborLocalAs = globalAs;
}
+ this.errorHandling = OpenConfigMappingUtil.getRevisedErrorHandling(role, peerGroup, neighbor);
this.bgpPeer = new BGPPeer(tableTypeRegistry, this.neighborAddress, peerGroupName, rib, role, clusterId,
neighborLocalAs, BgpPeer.this.rpcRegistry, afiSafisAdvertized, gracefulTables, BgpPeer.this);
this.prefs = new BGPSessionPreferences(neighborLocalAs, hold, rib.getBgpIdentifier(),
public synchronized int getGracefulRestartTimer() {
return this.bgpPeerSingletonService.gracefulRestartTimer;
}
+
+ @Nullable
+ public synchronized Optional<RevisedErrorHandlingSupport> getErrorHandling() {
+ return Optional.ofNullable(this.bgpPeerSingletonService.errorHandling);
+ }
}
import org.opendaylight.protocol.bgp.mode.impl.add.all.paths.AllPathSelection;
import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandlingSupport;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
import org.opendaylight.protocol.concepts.KeyMapping;
import org.opendaylight.protocol.util.Ipv4Util;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.BgpCommonAfiSafiList;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborGroup;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.BgpNeighborTransportConfig;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandling;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflector;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
}
return null;
}
+
+ @Nullable
+ static RevisedErrorHandlingSupport getRevisedErrorHandling(final PeerRole role,final PeerGroup peerGroup,
+ final Neighbor neighbor) {
+ Boolean enabled = getRevisedErrorHandling(neighbor);
+ if (enabled == null) {
+ enabled = getRevisedErrorHandling(peerGroup);
+ }
+ if (!Boolean.TRUE.equals(enabled)) {
+ return null;
+ }
+ switch (role) {
+ case Ebgp:
+ return RevisedErrorHandlingSupportImpl.forExternalPeer();
+ case Ibgp:
+ case Internal:
+ case RrClient:
+ return RevisedErrorHandlingSupportImpl.forInternalPeer();
+ default:
+ throw new IllegalStateException("Unhandled role " + role);
+ }
+ }
+
+ @Nullable
+ private static @org.eclipse.jdt.annotation.Nullable Boolean getRevisedErrorHandling(final BgpNeighborGroup group) {
+ if (group == null) {
+ return null;
+ }
+ final ErrorHandling errorHandling = group.getErrorHandling();
+ if (errorHandling == null) {
+ return null;
+ }
+ final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling
+ .Config config = errorHandling.getConfig();
+ return config == null ? null : config.isTreatAsWithdraw();
+ }
}
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
final Ipv4Address peerAddress, final RIBImpl ribImpl, final BgpParameters bgpParameters,
final PeerRole peerRole, final BGPPeerRegistry bgpPeerRegistry, final Set<TablesKey> afiSafiAdvertised,
final Set<TablesKey> gracefulAfiSafiAdvertised) {
+ final BgpPeer bgpPeer = Mockito.mock(BgpPeer.class);
+ doReturn(Optional.empty()).when(bgpPeer).getErrorHandling();
return configurePeer(tableRegistry, peerAddress, ribImpl, bgpParameters, peerRole, bgpPeerRegistry,
- afiSafiAdvertised, gracefulAfiSafiAdvertised, null);
+ afiSafiAdvertised, gracefulAfiSafiAdvertised, bgpPeer);
}
static BGPPeer configurePeer(final BGPTableTypeRegistryConsumer tableRegistry,
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
afiSafiAdvertised.add(IPV6_TABLES_KEY);
final BgpPeer bgpPeer = Mockito.mock(BgpPeer.class);
Mockito.doReturn(GRACEFUL_RESTART_TIME).when(bgpPeer).getGracefulRestartTimer();
+ Mockito.doReturn(Optional.empty()).when(bgpPeer).getErrorHandling();
Mockito.doReturn(createParameter(false, true, Collections.singletonMap(TABLES_KEY, false))
.getOptionalCapabilities()).when(bgpPeer).getBgpFixedCapabilities();
this.peer = configurePeer(this.tableRegistry, PEER1, this.ribImpl, parameters, PeerRole.Ibgp,
rib.instantiateServiceInstance();
assertTablesExists(tables);
rib.onGlobalContextUpdated(this.schemaService.getGlobalContext());
- final BGPPeer peer = new BGPPeer(this.tableRegistry, this.localAddress, rib, PeerRole.Ibgp, null,
- Collections.emptySet(), Collections.emptySet());
+ final BGPPeer peer = AbstractAddPathTest.configurePeer(this.tableRegistry, this.localAddress.getIpv4Address(),
+ rib, null, PeerRole.Ibgp, new StrictBGPPeerRegistry());
peer.instantiateServiceInstance();
final ListenerRegistration<?> reg = this.mock.registerUpdateListener(peer);
reg.close();
rib.instantiateServiceInstance();
rib.onGlobalContextUpdated(this.schemaService.getGlobalContext());
assertTablesExists(tables);
- final BGPPeer peer = new BGPPeer(this.tableRegistry, this.localAddress, rib, PeerRole.Ibgp, null,
- Collections.emptySet(), Collections.emptySet());
+ final BGPPeer peer = AbstractAddPathTest.configurePeer(this.tableRegistry, this.localAddress.getIpv4Address(),
+ rib, null, PeerRole.Ibgp, new StrictBGPPeerRegistry());
peer.instantiateServiceInstance();
final ListenerRegistration<?> reg = this.mock.registerUpdateListener(peer);
reg.close();
@Test
public void testClassicPeer() throws Exception {
- this.classic = new BGPPeer(this.tableRegistry, this.neighborAddress, getRib(), PeerRole.Ibgp, null,
- Collections.emptySet(), Collections.emptySet());
+ this.classic = AbstractAddPathTest.configurePeer(this.tableRegistry, this.neighborAddress.getIpv4Address(),
+ getRib(), null, PeerRole.Ibgp, new StrictBGPPeerRegistry());
this.classic.instantiateServiceInstance();
this.mockSession();
assertEquals(this.neighborAddress.getIpv4Address().getValue(), this.classic.getName());
assertEquals(3, this.routes.size());
//create new peer so that it gets advertized routes from RIB
- final BGPPeer testingPeer = new BGPPeer(this.tableRegistry, this.neighborAddress, getRib(), PeerRole.Ibgp,
- null, Collections.emptySet(), Collections.emptySet());
+ final BGPPeer testingPeer = AbstractAddPathTest.configurePeer(this.tableRegistry, this.neighborAddress.getIpv4Address(),
+ getRib(), null, PeerRole.Ibgp, new StrictBGPPeerRegistry());
testingPeer.instantiateServiceInstance();
testingPeer.onSessionUp(this.session);
assertEquals(3, this.routes.size());
ribImpl.instantiateServiceInstance();
ribImpl.onGlobalContextUpdated(this.schemaService.getGlobalContext());
- final BGPPeer bgpPeer = new BGPPeer(this.tableRegistry, neighbor, ribImpl, PeerRole.Ibgp, null,
- AFI_SAFIS_ADVERTIZED, Collections.emptySet());
+ final BGPPeer bgpPeer = AbstractAddPathTest.configurePeer(this.tableRegistry, neighbor.getIpv4Address(), ribImpl,
+ null, PeerRole.Ibgp, this.serverRegistry, AFI_SAFIS_ADVERTIZED, Collections.emptySet());
bgpPeer.instantiateServiceInstance();
final BGPSessionImpl bgpSession = new BGPSessionImpl(bgpPeer, this.speakerListener, this.classicOpen,
this.classicOpen.getHoldTimer(), null);
ribImpl.instantiateServiceInstance();
ribImpl.onGlobalContextUpdated(this.schemaService.getGlobalContext());
- final BGPPeer bgpPeer = new BGPPeer(this.tableRegistry, neighbor, ribImpl, PeerRole.Ibgp, null,
- AFI_SAFIS_ADVERTIZED, Collections.emptySet());
+ final BGPPeer bgpPeer = AbstractAddPathTest.configurePeer(this.tableRegistry, neighbor.getIpv4Address(), ribImpl,
+ null, PeerRole.Ibgp, this.serverRegistry, AFI_SAFIS_ADVERTIZED, Collections.emptySet());
bgpPeer.instantiateServiceInstance();
final BGPSessionImpl bgpSession = new BGPSessionImpl(bgpPeer, this.speakerListener, this.classicOpen,
this.classicOpen.getHoldTimer(), null);
import org.opendaylight.protocol.bgp.mode.impl.add.n.paths.AddPathBestNPathSelection;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.RevisedErrorHandlingSupportImpl;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafis;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafisBuilder;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ConfigBuilder;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandlingBuilder;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.RouteReflectorBuilder;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.TimersBuilder;
import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
.setRestartTime(restartTimer)
.build();
}
+
+ @Test
+ public void getRevisedErrorHandlingTest() {
+ final NeighborBuilder neighbor = new NeighborBuilder();
+ final PeerGroupBuilder peerGroup = new PeerGroupBuilder();
+ final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling.ConfigBuilder errorHandlingConfig =
+ new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error.handling.ConfigBuilder();
+ // error handling not set -> null
+ assertNull(OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ibgp, peerGroup.build(),
+ neighbor.build()));
+ // error handling for peer group disabled, neighbor not set -> null
+ peerGroup.setErrorHandling(new ErrorHandlingBuilder()
+ .setConfig(errorHandlingConfig.setTreatAsWithdraw(false).build())
+ .build());
+ assertNull(OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ibgp, peerGroup.build(),
+ neighbor.build()));
+ // error handling for peer group enabled, neighbor not set, Igp -> error handling for internal peer
+ peerGroup.setErrorHandling(new ErrorHandlingBuilder()
+ .setConfig(errorHandlingConfig.setTreatAsWithdraw(true).build())
+ .build());
+ assertEquals(RevisedErrorHandlingSupportImpl.forInternalPeer(),
+ OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ibgp, peerGroup.build(), neighbor.build()));
+ // error handling for peer group enabled, neighbor disabled -> null
+ neighbor.setErrorHandling(new ErrorHandlingBuilder()
+ .setConfig(errorHandlingConfig.setTreatAsWithdraw(false).build())
+ .build());
+ assertNull(OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ibgp, peerGroup.build(),
+ neighbor.build()));
+ // error handling for peer group enabled, neighbor enabled, Igb -> error handling for internal peer
+ neighbor.setErrorHandling(new ErrorHandlingBuilder()
+ .setConfig(errorHandlingConfig.setTreatAsWithdraw(true).build())
+ .build());
+ assertEquals(RevisedErrorHandlingSupportImpl.forInternalPeer(),
+ OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ibgp, peerGroup.build(), neighbor.build()));
+ // error handling for peer group enabled, neighbor enabled, Egb -> error handling for external peer
+ neighbor.setErrorHandling(new ErrorHandlingBuilder()
+ .setConfig(errorHandlingConfig.setTreatAsWithdraw(true).build())
+ .build());
+ assertEquals(RevisedErrorHandlingSupportImpl.forExternalPeer(),
+ OpenConfigMappingUtil.getRevisedErrorHandling(PeerRole.Ebgp, peerGroup.build(), neighbor.build()));
+ }
}
\ No newline at end of file
import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
import org.opendaylight.protocol.bgp.parser.BGPError;
import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
+import org.opendaylight.protocol.bgp.parser.spi.PeerConstraint;
import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
public void closeWithoutMessage() {
close();
}
+
+ @Override
+ public <T extends PeerConstraint> void addDecoderConstraint(final Class<T> constraintClass,
+ final T constraint) {
+ // No-op
+ }
}
}
import java.util.Set;
import javax.annotation.Nonnull;
import org.opendaylight.protocol.bgp.parser.GracefulRestartUtil;
+import org.opendaylight.protocol.bgp.parser.spi.PeerConstraint;
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.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
* Close peer session without sending Notification message.
*/
void closeWithoutMessage();
+
+ /**
+ * Add peer constraint to session pipeline decoder.
+ */
+ <T extends PeerConstraint> void addDecoderConstraint(Class<T> constraintClass, T constraint);
}