package org.opendaylight.controller.config.yang.bgp.rib.impl;
import com.google.common.base.Charsets;
-import com.google.common.collect.Lists;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.net.InetAddresses;
import io.netty.util.concurrent.Future;
-
import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-
-import org.opendaylight.bgpcep.tcpmd5.KeyMapping;
+import java.util.Map;
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
+import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenconfigMapper;
+import org.opendaylight.protocol.bgp.openconfig.spi.InstanceConfigurationIdentifier;
+import org.opendaylight.protocol.bgp.openconfig.spi.pojo.BGPPeerInstanceConfiguration;
+import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
+import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
import org.opendaylight.protocol.bgp.rib.impl.StrictBGPPeerRegistry;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
+import org.opendaylight.protocol.util.Ipv6Util;
+import org.opendaylight.tcpmd5.api.KeyMapping;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParametersBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.c.parameters.As4BytesCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.c.parameters.as4.bytes._case.As4BytesCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParameters;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilities;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.OptionalCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.CParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.bgp.parameters.optional.capabilities.c.parameters.As4BytesCapabilityBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.MultiprotocolCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.open.bgp.parameters.c.parameters.multiprotocol._case.MultiprotocolCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.AddPathCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.GracefulRestartCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.MultiprotocolCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.add.path.capability.AddressFamilies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.tcpmd5.cfg.rev140427.Rfc2385Key;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(BGPPeerModule.class);
public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
super(identifier, dependencyResolver);
}
public BGPPeerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final BGPPeerModule oldModule,
- final java.lang.AutoCloseable oldInstance) {
+ final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final BGPPeerModule oldModule,
+ final java.lang.AutoCloseable oldInstance) {
super(identifier, dependencyResolver, oldModule, oldInstance);
}
@Override
protected void customValidation() {
- JmxAttributeValidationException.checkNotNull(getHost(), "value is not set.", hostJmxAttribute);
+ final IpAddress host = getHost();
+ JmxAttributeValidationException.checkNotNull(host, "value is not set.", hostJmxAttribute);
+ JmxAttributeValidationException.checkCondition(host.getIpv4Address() != null || host.getIpv6Address() != null,
+ "Unexpected host", hostJmxAttribute);
+
JmxAttributeValidationException.checkNotNull(getPort(), "value is not set.", portJmxAttribute);
- if (getPassword() != null) {
+ if (getOptionaPassword(getPassword()).isPresent()) {
/*
* This is a nasty hack, but we don't have another clean solution. We cannot allow
* password being set if the injected dispatcher does not have the optional
* should something like isMd5ServerSupported()
*/
- RIBImplModuleMXBean ribProxy = dependencyResolver.newMXBeanProxy(getRib(), RIBImplModuleMXBean.class);
- BGPDispatcherImplModuleMXBean bgpDispatcherProxy = dependencyResolver.newMXBeanProxy(
- ribProxy.getBgpDispatcher(), BGPDispatcherImplModuleMXBean.class);
- boolean isMd5Supported = bgpDispatcherProxy.getMd5ChannelFactory() != null;
+ final RIBImplModuleMXBean ribProxy = this.dependencyResolver.newMXBeanProxy(getRib(), RIBImplModuleMXBean.class);
+ final BGPDispatcherImplModuleMXBean bgpDispatcherProxy = this.dependencyResolver.newMXBeanProxy(
+ ribProxy.getBgpDispatcher(), BGPDispatcherImplModuleMXBean.class);
+ final boolean isMd5Supported = bgpDispatcherProxy.getMd5ChannelFactory() != null;
JmxAttributeValidationException.checkCondition(isMd5Supported,
- "Underlying dispatcher does not support MD5 clients", passwordJmxAttribute);
+ "Underlying dispatcher does not support MD5 clients", passwordJmxAttribute);
+
+ }
+ if (getPeerRole() != null) {
+ final boolean isNotPeerRoleInternal= getPeerRole() != PeerRole.Internal;
+ JmxAttributeValidationException.checkCondition(isNotPeerRoleInternal,
+ "Internal Peer Role is reserved for Application Peer use.", peerRoleJmxAttribute);
}
}
private InetSocketAddress createAddress() {
final IpAddress ip = getHost();
+ Preconditions.checkArgument(ip.getIpv4Address() != null || ip.getIpv6Address() != null, "Failed to handle host %s", ip);
if (ip.getIpv4Address() != null) {
return new InetSocketAddress(InetAddresses.forString(ip.getIpv4Address().getValue()), getPort().getValue());
- } else if (ip.getIpv6Address() != null) {
- return new InetSocketAddress(InetAddresses.forString(ip.getIpv6Address().getValue()), getPort().getValue());
- } else {
- throw new IllegalStateException("Failed to handle host " + getHost());
}
+ return new InetSocketAddress(InetAddresses.forString(ip.getIpv6Address().getValue()), getPort().getValue());
}
@Override
final List<BgpParameters> tlvs = getTlvs(r);
final AsNumber remoteAs = getAsOrDefault(r);
- final String password = getPasswordOrNull();
+ final BGPSessionPreferences prefs = new BGPSessionPreferences(r.getLocalAs(), getHoldtimer(), r.getBgpIdentifier(), remoteAs, tlvs);
+ final BGPPeer bgpClientPeer;
+ final IpAddress host = getNormalizedHost();
+ if (getPeerRole() != null) {
+ bgpClientPeer = new BGPPeer(peerName(host), r, getPeerRole(), getSimpleRoutingPolicy(), getRpcRegistryDependency());
+ } else {
+ bgpClientPeer = new BGPPeer(peerName(host), r, PeerRole.Ibgp, getSimpleRoutingPolicy(), getRpcRegistryDependency());
+ }
+
+ bgpClientPeer.registerRootRuntimeBean(getRootRuntimeBeanRegistratorWrapper());
- final BGPSessionPreferences prefs = new BGPSessionPreferences(r.getLocalAs(), getHoldtimer(), r.getBgpIdentifier(), tlvs);
- final BGPPeer bgpClientPeer = new BGPPeer(peerName(getHostWithoutValue()), r);
+ getPeerRegistryBackwards().addPeer(host, bgpClientPeer, prefs);
- getPeerRegistryBackwards().addPeer(getHostWithoutValue(), bgpClientPeer, prefs);
+ final BGPPeerModuleTracker moduleTracker = new BGPPeerModuleTracker(r.getOpenConfigProvider());
+ moduleTracker.onInstanceCreate();
- final AutoCloseable peerCloseable = new AutoCloseable() {
+ final CloseableNoEx peerCloseable = new CloseableNoEx() {
@Override
- public void close() throws Exception {
+ public void close() {
bgpClientPeer.close();
- getPeerRegistryBackwards().removePeer(getHostWithoutValue());
+ getPeerRegistryBackwards().removePeer(host);
+ moduleTracker.onInstanceClose();
}
};
// Initiate connection
if(getInitiateConnection()) {
- final Future<Void> cf = initiateConnection(createAddress(), password, remoteAs, getPeerRegistryBackwards());
- return new AutoCloseable() {
+ final Future<Void> cf = initiateConnection(createAddress(), getOptionaPassword(getPassword()), getPeerRegistryBackwards());
+ return new CloseableNoEx() {
@Override
- public void close() throws Exception {
+ public void close() {
cf.cancel(true);
peerCloseable.close();
}
}
}
- private String getPasswordOrNull() {
- final String password;
- if (getPassword() != null) {
- password = getPassword().getValue();
- } else {
- password = null;
- }
- return password;
+ private interface CloseableNoEx extends AutoCloseable {
+ @Override
+ void close();
}
- private AsNumber getAsOrDefault(RIB r) {
+ private AsNumber getAsOrDefault(final RIB r) {
// Remote AS number defaults to our local AS
final AsNumber remoteAs;
if (getRemoteAs() != null) {
return remoteAs;
}
- private List<BgpParameters> getTlvs(RIB r) {
- final List<BgpParameters> tlvs = Lists.newArrayList();
- tlvs.add(new BgpParametersBuilder().setCParameters(
- new As4BytesCaseBuilder().setAs4BytesCapability(new As4BytesCapabilityBuilder().setAsNumber(r.getLocalAs()).build()).build()).build());
+ private List<BgpParameters> getTlvs(final RIB r) {
+ final List<BgpParameters> tlvs = new ArrayList<>();
+ final List<OptionalCapabilities> caps = new ArrayList<>();
+ caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().setAs4BytesCapability(
+ new As4BytesCapabilityBuilder().setAsNumber(r.getLocalAs()).build()).build()).build());
+ caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
+ new CParameters1Builder().setGracefulRestartCapability(new GracefulRestartCapabilityBuilder().build()).build()).build()).build());
+
+ if (getRouteRefresh()) {
+ caps.add(new OptionalCapabilitiesBuilder().setCParameters(MultiprotocolCapabilitiesUtil.RR_CAPABILITY).build());
+ }
+
+ if (!getAddPathDependency().isEmpty()) {
+ final List<AddressFamilies> addPathFamilies = filterAddPathDependency(getAddPathDependency());
+ caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
+ new CParameters1Builder().setAddPathCapability(new AddPathCapabilityBuilder().setAddressFamilies(addPathFamilies).build()).build()).build()).build());
+ }
for (final BgpTableType t : getAdvertizedTableDependency()) {
if (!r.getLocalTables().contains(t)) {
LOG.info("RIB instance does not list {} in its local tables. Incoming data will be dropped.", t);
}
- tlvs.add(new BgpParametersBuilder().setCParameters(
- new MultiprotocolCaseBuilder().setMultiprotocolCapability(new MultiprotocolCapabilityBuilder(t).build()).build()).build());
+ caps.add(new OptionalCapabilitiesBuilder().setCParameters(new CParametersBuilder().addAugmentation(CParameters1.class,
+ new CParameters1Builder().setMultiprotocolCapability(new MultiprotocolCapabilityBuilder(t).build()).build()).build()).build());
}
+ tlvs.add(new BgpParametersBuilder().setOptionalCapabilities(caps).build());
return tlvs;
}
- public IpAddress getHostWithoutValue() {
- // FIXME we need to remove field "value" from IpAddress since equals does not work as expected when value being present
- // Remove after this bug is fixed https://bugs.opendaylight.org/show_bug.cgi?id=1276
- final IpAddress host = super.getHost();
- if(host.getIpv4Address() != null) {
- return new IpAddress(host.getIpv4Address());
- } else if(host.getIpv6Address() != null){
- return new IpAddress(host.getIpv6Address());
+ private List<AddressFamilies> filterAddPathDependency(final List<AddressFamilies> addPathDependency) {
+ final Map<BgpTableType, AddressFamilies> filteredFamilies = new HashMap<BgpTableType, AddressFamilies>();
+ for (final AddressFamilies family : addPathDependency) {
+ final BgpTableType key = new BgpTableTypeImpl(family.getAfi(), family.getSafi());
+ if (!filteredFamilies.containsKey(key)) {
+ filteredFamilies.put(key, family);
+ } else {
+ LOG.info("Ignoring Add-path dependency {}", family);
+ }
}
+ return new ArrayList<AddressFamilies>(filteredFamilies.values());
+ }
- throw new IllegalArgumentException("Unexpected host " + host);
+ public IpAddress getNormalizedHost() {
+ final IpAddress host = getHost();
+ if(host.getIpv6Address() != null){
+ return new IpAddress(Ipv6Util.getFullForm(host.getIpv6Address()));
+ }
+ return host;
}
- private io.netty.util.concurrent.Future<Void> initiateConnection(final InetSocketAddress address, final String password, final AsNumber remoteAs, final BGPPeerRegistry registry) {
- final KeyMapping keys;
- if (password != null) {
+ private io.netty.util.concurrent.Future<Void> initiateConnection(final InetSocketAddress address, final Optional<Rfc2385Key> password, final BGPPeerRegistry registry) {
+ KeyMapping keys = null;
+ if (password.isPresent()) {
keys = new KeyMapping();
- keys.put(address.getAddress(), password.getBytes(Charsets.US_ASCII));
- } else {
- keys = null;
+ keys.put(address.getAddress(), password.get().getValue().getBytes(Charsets.US_ASCII));
}
final RIB rib = getRibDependency();
- return rib.getDispatcher().createReconnectingClient(address, remoteAs, registry, rib.getTcpStrategyFactory(),
- rib.getSessionStrategyFactory(), keys);
+ final Optional<KeyMapping> optionalKey = Optional.fromNullable(keys);
+ return rib.getDispatcher().createReconnectingClient(address, registry, getRetrytimer(), optionalKey);
}
private BGPPeerRegistry getPeerRegistryBackwards() {
return null;
}
+ private final class BGPPeerModuleTracker implements BGPConfigModuleTracker {
+
+ private final BGPOpenconfigMapper<BGPPeerInstanceConfiguration> neighborProvider;
+ private final BGPPeerInstanceConfiguration bgpPeerInstanceConfiguration;
+
+ public BGPPeerModuleTracker(final Optional<BGPOpenConfigProvider> openconfigProvider) {
+ if (openconfigProvider.isPresent()) {
+ this.neighborProvider = openconfigProvider.get().getOpenConfigMapper(BGPPeerInstanceConfiguration.class);
+ } else {
+ this.neighborProvider = null;
+ }
+ final InstanceConfigurationIdentifier identifier = new InstanceConfigurationIdentifier(getIdentifier().getInstanceName());
+ this.bgpPeerInstanceConfiguration = new BGPPeerInstanceConfiguration(identifier, Rev130715Util.getIpvAddress(getNormalizedHost()),
+ Rev130715Util.getPort(getPort().getValue()), getHoldtimer(), getPeerRole(), getInitiateConnection(),
+ getAdvertizedTableDependency(), Rev130715Util.getASNumber(getAsOrDefault(getRibDependency()).getValue()),
+ getOptionaPassword(getPassword()), getAddPathDependency());
+ }
+
+ @Override
+ public void onInstanceCreate() {
+ if (this.neighborProvider != null) {
+ this.neighborProvider.writeConfiguration(this.bgpPeerInstanceConfiguration);
+ }
+ }
+
+ @Override
+ public void onInstanceClose() {
+ if (this.neighborProvider != null) {
+ this.neighborProvider.removeConfiguration(this.bgpPeerInstanceConfiguration);
+ }
+ }
+
+ }
+
+ private Optional<Rfc2385Key> getOptionaPassword(final Rfc2385Key password) {
+ return password != null && ! password.getValue().isEmpty() ? Optional.of(password) : Optional.<Rfc2385Key>absent();
+ }
+
}