public final class PcepApiBundleTest extends AbstractBundleTest {
@Override
protected Collection<String> prerequisiteBundles() {
- return Lists.newArrayList("concepts", "rsvp-api", "util");
+ return Lists.newArrayList("concepts", "rsvp-api", "tcpmd5-api", "util");
}
@Override
protected Collection<String> prerequisiteBundles() {
return Lists.newArrayList("concepts", "pcep-api", "pcep-spi", "pcep-api-config", "pcep-ietf-stateful02", "pcep-ietf-stateful07", "pcep-topology-api",
"pcep-tunnel-api", "rsvp-api", "programming-api", "programming-topology-api", "topology-api", "topology-tunnel-api",
- "programming-tunnel-api", "util");
+ "programming-tunnel-api", "tcpmd5-api", "tcpmd5-jni", "tcpmd5-netty", "tcpmd5-nio", "util");
}
@Override
public final class PcepSpiBundleTest extends AbstractBundleTest {
@Override
protected Collection<String> prerequisiteBundles() {
- return Lists.newArrayList("concepts", "pcep-api", "rsvp-api", "util");
+ return Lists.newArrayList("concepts", "pcep-api", "rsvp-api", "tcpmd5-api", "util");
}
@Override
mavenBundle("org.opendaylight.bgpcep", "pcep-spi").versionAsInProject(), //
mavenBundle("org.opendaylight.bgpcep", "pcep-ietf-stateful02").versionAsInProject(), //
mavenBundle("org.opendaylight.bgpcep", "pcep-ietf-stateful07").versionAsInProject(), //
+ mavenBundle("org.opendaylight.bgpcep", "tcpmd5-api").versionAsInProject(), //
+ mavenBundle("org.opendaylight.bgpcep", "tcpmd5-jni").versionAsInProject(), //
+ mavenBundle("org.opendaylight.bgpcep", "tcpmd5-netty").versionAsInProject(), //
+ mavenBundle("org.opendaylight.bgpcep", "tcpmd5-nio").versionAsInProject(), //
mavenBundle("org.opendaylight.bgpcep", "topology-api").versionAsInProject(), //
mavenBundle("org.opendaylight.bgpcep", "topology-tunnel-api").versionAsInProject(), //
mavenBundle("org.opendaylight.bgpcep", "programming-topology-api").versionAsInProject(), //
base "config:service-type";
config:java-class "org.opendaylight.protocol.pcep.PCEPSessionProposalFactory";
}
-
}
<groupId>${project.groupId}</groupId>
<artifactId>rsvp-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-api</artifactId>
+ </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
import java.net.InetSocketAddress;
+import org.opendaylight.bgpcep.tcpmd5.KeyMapping;
import org.opendaylight.protocol.framework.SessionListenerFactory;
/**
public interface PCEPDispatcher {
/**
* Creates server. Each server needs three factories to pass their instances to client sessions.
- *
+ *
* @param address to be bound with the server
* @param listenerFactory to create listeners for clients
* @return instance of PCEPServer
*/
ChannelFuture createServer(InetSocketAddress address, SessionListenerFactory<PCEPSessionListener> listenerFactory);
+
+ /**
+ * Creates server. Each server needs three factories to pass their instances to client sessions.
+ *
+ * @param address to be bound with the server
+ * @param keys RFC2385 key mapping
+ * @param listenerFactory to create listeners for clients
+ * @return instance of PCEPServer
+ */
+ ChannelFuture createServer(InetSocketAddress address, KeyMapping keys, SessionListenerFactory<PCEPSessionListener> listenerFactory);
}
<groupId>${project.groupId}</groupId>
<artifactId>pcep-ietf-stateful02</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-netty-cfg</artifactId>
+ </dependency>
<!--test dependencies -->
<dependency>
final PCEPDispatcherImpl instance = new PCEPDispatcherImpl(
getPcepExtensionsDependency().getMessageHandlerRegistry(),
- negFactory, getBossGroupDependency(), getWorkerGroupDependency());
+ negFactory, getBossGroupDependency(), getWorkerGroupDependency(),
+ getMd5ChannelFactoryDependency(), getMd5ServerChannelFactoryDependency());
return instance;
}
}
import pcep { prefix pcep; revision-date 2013-04-09; }
import config-pcep-spi { prefix spi; revision-date 2013-11-15; }
import netty { prefix netty; revision-date 2013-11-19; }
+ import odl-tcpmd5-netty-cfg { prefix tcpmd5; revision-date 2014-04-27; }
organization "Cisco Systems, Inc.";
identity pcep-parser-ietf-stateful07 {
base config:module-type;
config:provided-service spi:extension;
- config:java-name-prefix IetfStateful07PCEPParser;
+ config:java-name-prefix IetfStateful07PCEPParser;
}
augment "/config:modules/config:module/config:configuration" {
}
}
- identity pcep-parser-ietf-initiated00 {
- base config:module-type;
+ identity pcep-parser-ietf-initiated00 {
+ base config:module-type;
config:provided-service spi:extension;
config:java-name-prefix IetfInitiated00PCEPParser;
}
augment "/config:modules/config:module/config:configuration" {
case pcep-parser-ietf-initiated00 {
when "/config:modules/config:module/config:type = 'pcep-parser-ietf-initiated00'";
- }
+ }
}
identity pcep-parser-ietf-stateful02 {
}
}
- identity pcep-parser-crabbe-initiated00 {
- base config:module-type;
+ identity pcep-parser-crabbe-initiated00 {
+ base config:module-type;
config:provided-service spi:extension;
config:java-name-prefix CrabbeInitiated00PCEPParser;
}
}
}
}
+
+ container md5-channel-factory {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity tcpmd5:md5-channel-factory;
+ }
+ }
+ }
+
+ container md5-server-channel-factory {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity tcpmd5:md5-server-channel-factory;
+ }
+ }
+ }
}
}
<groupId>${project.groupId}</groupId>
<artifactId>util</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-netty</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
*/
package org.opendaylight.protocol.pcep.impl;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import java.net.InetSocketAddress;
+import org.opendaylight.bgpcep.tcpmd5.KeyMapping;
+import org.opendaylight.bgpcep.tcpmd5.netty.MD5ChannelFactory;
+import org.opendaylight.bgpcep.tcpmd5.netty.MD5ChannelOption;
+import org.opendaylight.bgpcep.tcpmd5.netty.MD5ServerChannelFactory;
import org.opendaylight.protocol.framework.AbstractDispatcher;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
public class PCEPDispatcherImpl extends AbstractDispatcher<PCEPSessionImpl, PCEPSessionListener> implements PCEPDispatcher, AutoCloseable {
private final SessionNegotiatorFactory<Message, PCEPSessionImpl, PCEPSessionListener> snf;
+ private final MD5ServerChannelFactory<?> scf;
+ private final MD5ChannelFactory<?> cf;
private final PCEPHandlerFactory hf;
+ private KeyMapping keys;
/**
* Creates an instance of PCEPDispatcherImpl, gets the default selector and opens it.
*/
public PCEPDispatcherImpl(final MessageRegistry registry,
- final SessionNegotiatorFactory<Message, PCEPSessionImpl, PCEPSessionListener> negotiatorFactory, EventLoopGroup bossGroup,
- EventLoopGroup workerGroup) {
+ final SessionNegotiatorFactory<Message, PCEPSessionImpl, PCEPSessionListener> negotiatorFactory, final EventLoopGroup bossGroup,
+ final EventLoopGroup workerGroup) {
+ this(registry, negotiatorFactory, bossGroup, workerGroup, null, null);
+ }
+
+ /**
+ * Creates an instance of PCEPDispatcherImpl, gets the default selector and opens it.
+ */
+ public PCEPDispatcherImpl(final MessageRegistry registry,
+ final SessionNegotiatorFactory<Message, PCEPSessionImpl, PCEPSessionListener> negotiatorFactory, final EventLoopGroup bossGroup,
+ final EventLoopGroup workerGroup, final MD5ChannelFactory<?> cf, final MD5ServerChannelFactory<?> scf) {
super(bossGroup, workerGroup);
+ this.cf = cf;
+ this.scf = scf;
this.snf = Preconditions.checkNotNull(negotiatorFactory);
this.hf = new PCEPHandlerFactory(registry);
}
@Override
- public ChannelFuture createServer(final InetSocketAddress address, final SessionListenerFactory<PCEPSessionListener> listenerFactory) {
- return super.createServer(address, new PipelineInitializer<PCEPSessionImpl>() {
+ public synchronized ChannelFuture createServer(final InetSocketAddress address, final SessionListenerFactory<PCEPSessionListener> listenerFactory) {
+ return createServer(address, null, listenerFactory);
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ protected void customizeBootstrap(final Bootstrap b) {
+ if (keys != null && !keys.isEmpty()) {
+ if (cf == null) {
+ throw new UnsupportedOperationException("No key access instance available, cannot use key mapping");
+ }
+ b.channelFactory(cf);
+ b.option(MD5ChannelOption.TCP_MD5SIG, keys);
+ }
+ }
+
+ @Override
+ protected void customizeBootstrap(final ServerBootstrap b) {
+ if (keys != null && !keys.isEmpty()) {
+ if (scf == null) {
+ throw new UnsupportedOperationException("No key access instance available, cannot use key mapping");
+ }
+ b.channelFactory(scf);
+ b.option(MD5ChannelOption.TCP_MD5SIG, keys);
+ }
+ }
+
+ @Override
+ public synchronized ChannelFuture createServer(final InetSocketAddress address, final KeyMapping keys,
+ final SessionListenerFactory<PCEPSessionListener> listenerFactory) {
+ this.keys = keys;
+ ChannelFuture ret = super.createServer(address, new PipelineInitializer<PCEPSessionImpl>() {
@Override
public void initializeChannel(final SocketChannel ch, final Promise<PCEPSessionImpl> promise) {
ch.pipeline().addLast(PCEPDispatcherImpl.this.hf.getDecoders());
ch.pipeline().addLast(PCEPDispatcherImpl.this.hf.getEncoders());
}
});
- }
- @Override
- public void close() {
+ this.keys = null;
+ return ret;
}
}
<artifactId>topology-tunnel-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-api-cfg</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-netty</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-netty-cfg</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
<groupId>${project.groupId}</groupId>
<artifactId>pcep-api-config</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>pcep-impl-config</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>programming-spi-config</artifactId>
<groupId>${project.groupId}</groupId>
<artifactId>topology-api-config</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>tcpmd5-api-cfg</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>ietf-inet-types</artifactId>
</dependency>
+
<!--test dependencies -->
<dependency>
<groupId>junit</groupId>
*/
package org.opendaylight.controller.config.yang.pcep.topology.provider;
+import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ReflectionException;
+
import org.opendaylight.bgpcep.pcep.topology.provider.PCEPTopologyProvider;
+import org.opendaylight.bgpcep.tcpmd5.KeyMapping;
import org.opendaylight.controller.config.api.JmxAttributeValidationException;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Charsets;
import com.google.common.net.InetAddresses;
/**
*
*/
public final class PCEPTopologyProviderModule extends
- org.opendaylight.controller.config.yang.pcep.topology.provider.AbstractPCEPTopologyProviderModule {
+org.opendaylight.controller.config.yang.pcep.topology.provider.AbstractPCEPTopologyProviderModule {
private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologyProviderModule.class);
public PCEPTopologyProviderModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
}
@Override
- public void validate() {
- super.validate();
+ public void customValidation() {
JmxAttributeValidationException.checkNotNull(getTopologyId(), "is not set.", this.topologyIdJmxAttribute);
JmxAttributeValidationException.checkNotNull(getListenAddress(), "is not set.", this.listenAddressJmxAttribute);
JmxAttributeValidationException.checkNotNull(getListenPort(), "is not set.", this.listenPortJmxAttribute);
JmxAttributeValidationException.checkNotNull(getStatefulPlugin(), "is not set.", this.statefulPluginJmxAttribute);
+ if (getPassword() != null) {
+ /*
+ * 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
+ * md5-server-channel-factory set.
+ *
+ * FIXME: this is a use case for Module interfaces, e.g. PCEPDispatcherImplModule
+ * should something like isMd5ServerSupported()
+ */
+ final MBeanServer srv = ManagementFactory.getPlatformMBeanServer();
+ Object scf;
+ try {
+ // FIXME: AbstractPCEPDispatcherImplModule.md5ServerChannelFactoryJmxAttribute.getAttributeName()
+ scf = srv.getAttribute(getDispatcher(), "Md5ServerChannelFactory");
+ JmxAttributeValidationException.checkCondition(scf != null, "Underlying dispatcher does not support MD5 server", this.passwordJmxAttribute);
+ } catch (AttributeNotFoundException | InstanceNotFoundException
+ | MBeanException | ReflectionException e) {
+ JmxAttributeValidationException.wrap(e, passwordJmxAttribute);
+ }
+ }
}
private InetAddress listenAddress() {
final InstanceIdentifier<Topology> topology = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class,
new TopologyKey(getTopologyId())).toInstance();
final InetSocketAddress address = new InetSocketAddress(listenAddress(), getListenPort().getValue());
+
+ final KeyMapping keys;
+ if (getPassword() != null) {
+ keys = new KeyMapping();
+ keys.put(InetAddresses.forString("0.0.0.0"), getPassword().getValue().getBytes(Charsets.UTF_8));
+ } else {
+ keys = null;
+ }
+
try {
- return PCEPTopologyProvider.create(getDispatcherDependency(), address, getSchedulerDependency(), getDataProviderDependency(),
+ return PCEPTopologyProvider.create(getDispatcherDependency(), address, keys, getSchedulerDependency(), getDataProviderDependency(),
getRpcRegistryDependency(), topology, getStatefulPluginDependency());
} catch (InterruptedException | ExecutionException e) {
LOG.error("Failed to instantiate topology provider at {}", address, e);
import network-topology { prefix nt; revision-date 2013-10-21; }
import pcep { prefix pcep; revision-date 2013-04-09; }
import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+ import odl-tcpmd5-cfg { prefix tcpmd5; revision-date 2014-04-27; }
organization "Cisco Systems, Inc.";
type inet:port-number;
default 4189;
}
+
+ leaf password {
+ type tcpmd5:rfc2385-key;
+ description "RFC2385 shared secret";
+ }
}
}
}
import java.util.concurrent.ExecutionException;
import org.opendaylight.bgpcep.programming.spi.InstructionScheduler;
+import org.opendaylight.bgpcep.tcpmd5.KeyMapping;
import org.opendaylight.bgpcep.topology.DefaultTopologyReference;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
}
public static PCEPTopologyProvider create(final PCEPDispatcher dispatcher, final InetSocketAddress address,
+ final KeyMapping keys,
final InstructionScheduler scheduler, final DataProviderService dataService, final RpcProviderRegistry rpcRegistry,
final InstanceIdentifier<Topology> topology, final TopologySessionListenerFactory listenerFactory)
throws InterruptedException, ExecutionException {