<artifactId>sxp-ep-provider</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ip-sgt-distribution-service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- GBP configuration -->
<dependency>
<type>xml</type>
<classifier>config</classifier>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ip-sgt-distribution-service</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sxp-ise-adapter</artifactId>
<artifactId>sxp-core</artifactId>
<version>${sxp.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-controller</artifactId>
+ <version>${sxp.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.sxp</groupId>
<artifactId>features</artifactId>
<groupId>org.opendaylight.groupbasedpolicy</groupId>
<artifactId>sxp-ep-provider</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>ip-sgt-distribution-service</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.groupbasedpolicy</groupId>
<artifactId>ios-xe-renderer</artifactId>
<type>xml</type>
<classifier>config</classifier>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>ip-sgt-distribution-service</artifactId>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
<dependency>
<groupId>org.opendaylight.groupbasedpolicy</groupId>
<artifactId>ios-xe-renderer</artifactId>
<bundle>mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ui-bundle/{{VERSION}}</bundle>
</feature>
+ <!--
+ SXP Distribution Service
+ -->
+ <feature name='odl-groupbasedpolicy-ip-sgt-distribution-service' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: ip-sgt-distribution-service'>
+ <feature version="${project.version}">odl-groupbasedpolicy-base</feature>
+ <feature version="${sxp.version}">odl-sxp-core</feature>
+ <feature version="${sxp.version}">odl-sxp-controller</feature>
+ <bundle>mvn:org.opendaylight.groupbasedpolicy/ip-sgt-distribution-service/{{VERSION}}</bundle>
+ <configfile finalname="${config.configfile.directory}/15-groupbasedpolicy-ip-sgt-distribution-service.xml">mvn:org.opendaylight.groupbasedpolicy/ip-sgt-distribution-service/{{VERSION}}/xml/config</configfile>
+ </feature>
+
<!--
NE Location Provider
-->
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-parent</artifactId>
+ <version>0.6.0-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>ip-sgt-distribution-service</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>groupbasedpolicy-ip-sgt-distribution-service</name>
+
+ <properties>
+ <sxp.version>1.4.0-SNAPSHOT</sxp.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-core</artifactId>
+ <version>${sxp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-api</artifactId>
+ <version>${sxp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-controller</artifactId>
+ <version>${sxp.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-inet-types-2013-07-15</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.sxp</groupId>
+ <artifactId>sxp-controller</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>groupbasedpolicy</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- testing dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.groupbasedpolicy</groupId>
+ <artifactId>groupbasedpolicy</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-module-junit4</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <!-- project build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:ip-sgt-distribution-service="urn:opendaylight:params:xml:ns:yang:controller:config:ip:sgt:distribution:service:cfg">
+ ip-sgt-distribution-service:ip-sgt-distribution-service
+ </type>
+ <name>ip-sgt-distribution-service</name>
+ </module>
+ </modules>
+ </data>
+
+ </configuration>
+
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:ip:sgt:distribution:service:cfg?module=ip-sgt-distribution-service-cfg&revision=2016-07-15</capability>
+ </required-capabilities>
+
+</snapshot>
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.config.yang.config.groupbasedpolicy.GroupbasedpolicyInstance;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl.IpSgtDistributionServiceImpl;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.IpSgtDistributionService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class IpSgtDistributionServiceInstance
+ implements ClusterSingletonService, IpSgtDistributionService, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(IpSgtDistributionServiceInstance.class);
+ private static final ServiceGroupIdentifier IDENTIFIER =
+ ServiceGroupIdentifier.create(GroupbasedpolicyInstance.GBP_SERVICE_GROUP_IDENTIFIER);
+ private IpSgtDistributionServiceImpl ipSgtDistributionServiceImpl;
+ private DataBroker dataBroker;
+ private SxpControllerService sxpService;
+ private IpAddress sourceIp;
+ private ClusterSingletonServiceProvider clusterSingletonService;
+ private ClusterSingletonServiceRegistration singletonServiceRegistration;
+
+ public IpSgtDistributionServiceInstance(final DataBroker dataBroker, final SxpControllerService sxpService,
+ final String sourceIp, final ClusterSingletonServiceProvider clusterSingletonService) {
+ this.dataBroker = Preconditions.checkNotNull(dataBroker);
+ this.sxpService = Preconditions.checkNotNull(sxpService);
+ this.sourceIp = new IpAddress(Preconditions.checkNotNull(sourceIp.toCharArray()));
+ this.clusterSingletonService = Preconditions.checkNotNull(clusterSingletonService);
+ }
+
+ public void initialize() {
+ LOG.info("Clustering session initiated for {}", this.getClass().getSimpleName());
+ singletonServiceRegistration = clusterSingletonService.registerClusterSingletonService(this);
+ }
+
+ @Override
+ public ServiceGroupIdentifier getIdentifier() {
+ return IDENTIFIER;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.info("Clustering provider closed for {}", this.getClass().getSimpleName());
+ if (singletonServiceRegistration != null) {
+ try {
+ singletonServiceRegistration.close();
+ } catch (Exception e) {
+ LOG.warn("{} closed unexpectedly", this.getClass().getSimpleName(), e);
+ }
+ singletonServiceRegistration = null;
+ }
+ }
+
+ @Override
+ public Future<RpcResult<Void>> removeIpSgtBindingFromPeer(RemoveIpSgtBindingFromPeerInput input) {
+ return ipSgtDistributionServiceImpl.removeIpSgtBindingFromPeer(input);
+ }
+
+ @Override
+ public Future<RpcResult<Void>> sendIpSgtBindingToPeer(SendIpSgtBindingToPeerInput input) {
+ return ipSgtDistributionServiceImpl.sendIpSgtBindingToPeer(input);
+ }
+
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+ LOG.info("Instance {} closed", this.getClass().getSimpleName());
+ try {
+ ipSgtDistributionServiceImpl.close();
+ } catch (Exception e) {
+ LOG.error("Closing {} wasnt succesfull", ipSgtDistributionServiceImpl.getClass().getSimpleName());
+ }
+ return Futures.immediateFuture(null);
+ }
+
+ @Override
+ public void instantiateServiceInstance() {
+ ipSgtDistributionServiceImpl = new IpSgtDistributionServiceImpl(dataBroker, sxpService, sourceIp);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg;
+
+import org.opendaylight.controller.sal.common.util.NoopAutoCloseable;
+
+public class IpSgtDistributionServiceModule extends org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg.AbstractIpSgtDistributionServiceModule {
+ public IpSgtDistributionServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public IpSgtDistributionServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg.IpSgtDistributionServiceModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return NoopAutoCloseable.INSTANCE;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg;
+public class IpSgtDistributionServiceModuleFactory extends org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg.AbstractIpSgtDistributionServiceModuleFactory {
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.IpSgtDistributionService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.Binding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.binding.PeerNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.databases.fields.MasterDatabase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
+public class IpSgtDistributionServiceImpl implements AutoCloseable, IpSgtDistributionService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(IpSgtDistributionServiceImpl.class);
+ public static final String SXP_NODE_DESCRIPTION = "ODL-GBP SXP node";
+ public static final String SXP_TOPOLOGY_ID = "sxp";
+ private final String SXP_NODE_ID;
+ private DataBroker dataBroker;
+ private IpAddress sourceIp;
+ private SxpCapableNodeListener nodeCollector;
+
+ public IpSgtDistributionServiceImpl(DataBroker dataBroker, SxpControllerService sxpService, IpAddress sourceIp) {
+ this.dataBroker = Preconditions.checkNotNull(dataBroker);
+ this.sourceIp = Preconditions.checkNotNull(sourceIp);
+ Preconditions.checkNotNull(sxpService);
+
+ if (sourceIp.getIpv4Address() != null) {
+ SXP_NODE_ID = sourceIp.getIpv4Address().getValue();
+ } else {
+ SXP_NODE_ID = sourceIp.getIpv6Address().getValue();
+ }
+ createSxpNode(sxpService);
+ nodeCollector = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID);
+
+ }
+
+ private void createSxpNode(SxpControllerService sxpService) {
+ AddNodeInput addNodeInput = new AddNodeInputBuilder().setNodeId(new NodeId(SXP_NODE_ID))
+ .setSourceIp(sourceIp)
+ .setDescription(SXP_NODE_DESCRIPTION)
+ .build();
+ Future<RpcResult<AddNodeOutput>> addNodeResult = sxpService.addNode(addNodeInput);
+ try {
+ if (!addNodeResult.get().getResult().isResult()) {
+ LOG.error("RPC add-node wasn't successfull");
+ }
+ } catch (Exception e) {
+ LOG.error("RPC add-node wasn't successfull");
+ }
+ }
+
+ @Override
+ public Future<RpcResult<Void>> sendIpSgtBindingToPeer(SendIpSgtBindingToPeerInput input) {
+ Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>();
+ boolean success = true;
+ for (Binding binding : input.getBinding()) {
+ success = transformChanges(binding, bindingsMap);
+ if (!success) {
+ break;
+ }
+ }
+ if (!success) {
+ return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build());
+ }
+ WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ bindingsMap.entrySet().forEach(bindingEntries -> {
+ String domainId = bindingEntries.getKey();
+ bindingEntries.getValue().entries().forEach(binding -> writeBinding(binding, domainId, wtx));
+ });
+ ListenableFuture<Void> submit = wtx.submit();
+ SettableFuture<RpcResult<Void>> future = SettableFuture.create();
+ Futures.addCallback(submit, new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ future.set(RpcResultBuilder.<Void>success().build());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ future.set(RpcResultBuilder.<Void>failed().build());
+
+ }
+
+ });
+ return future;
+ }
+
+ private boolean transformChanges(Binding binding, Map<String, Multimap<Sgt, IpPrefix>> bindingsMap) {
+ Sgt sgt = binding.getSgt();
+ IpPrefix addr = binding.getIpPrefix();
+ for (PeerNode peer : binding.getPeerNode()) {
+ String domainId = nodeCollector.getDomainIdForPeer((InstanceIdentifier<Node>) peer.getNodeIid());
+ if (domainId == null) {
+ LOG.debug("Node {} is not SXP capable", peer.getNodeIid());
+ return false;
+ }
+ Multimap<Sgt, IpPrefix> domainBindingMap = bindingsMap.get(domainId);
+ if (domainBindingMap == null) {
+ domainBindingMap = ArrayListMultimap.create();
+ bindingsMap.put(domainId, domainBindingMap);
+ }
+ domainBindingMap.get(sgt).add(addr);
+ }
+ return true;
+ }
+
+ private void writeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) {
+ IpPrefix addr = binding.getValue();
+ InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr);
+ MasterDatabaseBinding newBinding = createBinding(binding);
+ wtx.put(LogicalDatastoreType.CONFIGURATION, iid, newBinding);
+ }
+
+ private InstanceIdentifier<MasterDatabaseBinding> bindingIid(String domainId, IpPrefix prefix) {
+ return InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId(SXP_TOPOLOGY_ID)))
+ .child(Node.class,
+ new NodeKey(
+ new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(
+ SXP_NODE_ID)))
+ .augmentation(SxpNodeIdentity.class)
+ .child(SxpDomains.class)
+ .child(SxpDomain.class, new SxpDomainKey(domainId))
+ .child(MasterDatabase.class)
+ .child(MasterDatabaseBinding.class, new MasterDatabaseBindingKey(prefix))
+ .build();
+ }
+
+ private MasterDatabaseBinding createBinding(Entry<Sgt, IpPrefix> binding) {
+ return new MasterDatabaseBindingBuilder().setIpPrefix(binding.getValue())
+ .setSecurityGroupTag(binding.getKey())
+ .build();
+ }
+
+ @Override
+ public Future<RpcResult<Void>> removeIpSgtBindingFromPeer(RemoveIpSgtBindingFromPeerInput input) {
+ Map<String, Multimap<Sgt, IpPrefix>> bindingsMap = new HashMap<>();
+ boolean success = true;
+ for (Binding binding : input.getBinding()) {
+ success = transformChanges(binding, bindingsMap);
+ if (!success) {
+ break;
+ }
+ }
+ if (!success) {
+ return Futures.immediateCheckedFuture(RpcResultBuilder.<Void>failed().build());
+ }
+ WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ bindingsMap.entrySet().forEach(bindingEntries -> {
+ String domainId = bindingEntries.getKey();
+ bindingEntries.getValue().entries().forEach(binding -> removeBinding(binding, domainId, wtx));
+ });
+ ListenableFuture<Void> submit = wtx.submit();
+ SettableFuture<RpcResult<Void>> future = SettableFuture.create();
+ Futures.addCallback(submit, new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(Void result) {
+ future.set(RpcResultBuilder.<Void>success().build());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ future.set(RpcResultBuilder.<Void>failed().build());
+
+ }
+
+ });
+ return future;
+ }
+
+ private void removeBinding(Entry<Sgt, IpPrefix> binding, String domainId, WriteTransaction wtx) {
+ IpPrefix addr = binding.getValue();
+ InstanceIdentifier<MasterDatabaseBinding> iid = bindingIid(domainId, addr);
+ wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ }
+
+ @Override
+ public void close() throws Exception {
+ nodeCollector.close();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+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.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SxpConnectionAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.sxp.connection.fields.SxpConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.connection.fields.ConnectionTimersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.connections.fields.ConnectionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.connections.fields.connections.ConnectionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.ConnectionMode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SxpCapableNodeListener implements DataTreeChangeListener<SxpConnection> {
+
+ private String SXP_NODE_ID;
+ private ListenerRegistration<SxpCapableNodeListener> listenerRegistration;
+ private Map<InstanceIdentifier<Node>, String> sxpCapableNodes = new HashMap<>();
+ private DataBroker dataBroker;
+
+ public SxpCapableNodeListener(DataBroker dataBroker, String sxpNodeId) {
+ SXP_NODE_ID = sxpNodeId;
+ this.dataBroker = dataBroker;
+ DataTreeIdentifier<SxpConnection> iid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class)
+ .child(Node.class)
+ .augmentation(SxpConnectionAugmentation.class)
+ .child(SxpConnection.class)
+ .build());
+ listenerRegistration = dataBroker.registerDataTreeChangeListener(iid, this);
+ }
+
+ @Override
+ public synchronized void onDataTreeChanged(Collection<DataTreeModification<SxpConnection>> changes) {
+ changes.forEach((change) -> {
+ InstanceIdentifier<Node> nodeIid = change.getRootPath().getRootIdentifier().firstIdentifierOf(Node.class);
+ DataObjectModification<SxpConnection> rootNode = change.getRootNode();
+ String domainId = createDomainId(nodeIid);
+ switch (rootNode.getModificationType()) {
+ case DELETE: {
+ removeSxpDomain(domainId);
+ sxpCapableNodes.remove(nodeIid);
+ break;
+ }
+ case WRITE:
+ case SUBTREE_MODIFIED: {
+ createSxpDomain(rootNode.getDataAfter(), domainId);
+ sxpCapableNodes.put(nodeIid, domainId);
+ break;
+ }
+ }
+ });
+ }
+
+ private String createDomainId(InstanceIdentifier<Node> nodeIid) {
+ String topologyId = nodeIid.firstKeyOf(Topology.class).getTopologyId().getValue();
+ String nodeId = nodeIid.firstKeyOf(Node.class).getNodeId().getValue();
+ return topologyId + "/" + nodeId;
+ }
+
+ private void removeSxpDomain(String domainId) {
+ InstanceIdentifier<SxpDomain> iid = sxpDomainIid(domainId);
+ WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ wtx.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ wtx.submit();
+ }
+
+ private void createSxpDomain(SxpConnection sxpData, String domainId) {
+ IpAddress peerAddr = sxpData.getIpAddress();
+ PortNumber port = sxpData.getPortNumber();
+ String password = sxpData.getPassword();
+ InstanceIdentifier<SxpDomain> iid = sxpDomainIid(domainId);
+ SxpDomain domain = new SxpDomainBuilder().setDomainName(domainId)
+ .setConnections(new ConnectionsBuilder()
+ .setConnection(Collections.singletonList(new ConnectionBuilder().setPeerAddress(peerAddr)
+ .setTcpPort(port)
+ .setMode(ConnectionMode.Speaker)
+ .setPassword(password)
+ .setConnectionTimers(new ConnectionTimersBuilder().build())
+ .setDescription("Connection to " + domainId)
+ .build()))
+ .build())
+ .build();
+ WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ wtx.merge(LogicalDatastoreType.CONFIGURATION, iid, domain);
+ wtx.submit();
+ }
+
+ private InstanceIdentifier<SxpDomain> sxpDomainIid(String domainId) {
+ return InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId(IpSgtDistributionServiceImpl.SXP_TOPOLOGY_ID)))
+ .child(Node.class, new NodeKey(new NodeId(SXP_NODE_ID)))
+ .augmentation(SxpNodeIdentity.class)
+ .child(SxpDomains.class)
+ .child(SxpDomain.class, new SxpDomainKey(domainId))
+ .build();
+ }
+
+ synchronized String getDomainIdForPeer(InstanceIdentifier<Node> peer) {
+ return sxpCapableNodes.get(peer);
+ }
+
+ void close() {
+ listenerRegistration.close();
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ odl:use-default-for-reference-types="true">
+
+ <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/>
+ <reference id="clusterSingletonService" interface="org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider"/>
+ <odl:rpc-service id="sxpControllerService" interface="org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService"/>
+
+ <!-- Modules /-->
+ <bean id="ipSgtDistributionService" class="org.opendaylight.controller.config.yang.config.ip.sgt.distribution.service.cfg.IpSgtDistributionServiceInstance"
+ init-method="initialize" destroy-method="close">
+ <argument ref="dataBroker"/>
+ <argument ref="sxpControllerService"/>
+ <argument value="127.0.0.1"/>
+ <argument ref="clusterSingletonService"/>
+ </bean>
+</blueprint>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+module ip-sgt-distribution-service-cfg {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:ip:sgt:distribution:service:cfg";
+ prefix "ip-sgt-distribution-service-cfg";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+ import ietf-inet-types { prefix inet; revision-date 2013-07-15; }
+
+ description
+ "This module contains the base YANG definitions for
+ ip/sgt distribution service implementation.";
+
+ revision "2016-07-15" {
+ description
+ "Initial revision.";
+ }
+
+ identity ip-sgt-distribution-service {
+ base "config:module-type";
+
+ config:java-name-prefix IpSgtDistributionService;
+ }
+
+ // Augments the 'configuration' choice node under modules/module.
+ augment "/config:modules/config:module/config:configuration" {
+ case ip-sgt-distribution-service {
+ when "/config:modules/config:module/config:type = 'ip-sgt-distribution-service'";
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+module ip-sgt-distribution {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:ip:sgt:distribution";
+ prefix "ip-sgt-distribution";
+
+ import sxp-database { prefix sxp-database; revision-date 2016-03-08; }
+ import sxp-protocol { prefix sxppt; revision-date 2014-10-02; }
+ import ietf-inet-types { prefix inet; revision-date 2013-07-15; }
+ import network-topology { prefix nt; revision-date 2013-10-21; }
+ import yang-ext { prefix ext; revision-date 2013-07-09; }
+
+ description
+ "This module contains the base YANG definitions for
+ ip/sgt distribution models.";
+
+ revision "2016-07-15" {
+ description
+ "Initial revision.";
+ }
+
+ grouping rpc-fields {
+ list binding {
+ key "sgt ip-prefix";
+ leaf sgt {
+ type sxp-database:sgt;
+ }
+ leaf ip-prefix {
+ type inet:ip-prefix;
+ }
+ list peer-node {
+ key "node-iid";
+ leaf node-iid {
+ type instance-identifier;
+ }
+ }
+ }
+ }
+
+ grouping sxp-connection-fields {
+ container sxp-connection {
+ leaf ip-address {
+ type inet:ip-address;
+ }
+ leaf port-number {
+ type inet:port-number;
+ default 64999;
+ }
+ leaf password {
+ type string;
+ }
+ leaf version {
+ type sxppt:version;
+ default "version4";
+ }
+ }
+ }
+
+ rpc send-ip-sgt-binding-to-peer {
+ input {
+ uses rpc-fields;
+ }
+ }
+
+ rpc remove-ip-sgt-binding-from-peer {
+ input {
+ uses rpc-fields;
+ }
+ }
+
+ augment /nt:network-topology/nt:topology/nt:node {
+ ext:augment-identifier "sxp-connection-augmentation";
+ uses sxp-connection-fields;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.concurrent.Future;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+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.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.RemoveIpSgtBindingFromPeerInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SendIpSgtBindingToPeerInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.BindingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.rpc.fields.binding.PeerNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.AddNodeOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.controller.rev141002.SxpControllerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBinding;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.master.database.fields.MasterDatabaseBindingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.databases.fields.MasterDatabase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.util.concurrent.Futures;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(IpSgtDistributionServiceImpl.class)
+public class IpSgtDistributionServiceImplTest {
+
+ private final IpAddress ADDR = new IpAddress(new Ipv4Address("10.0.0.1"));
+ private final IpPrefix BINDING_ADDR = new IpPrefix(new Ipv4Prefix("192.168.50.1/32"));
+ private final Sgt BINDING_SGT = new Sgt(1010);
+ private final String NODE_ID = "node1";
+ private final String TOPOLOGY_ID = "test-topology";
+ private final String DOMAIN_ID = TOPOLOGY_ID + "/" + NODE_ID;
+ private final InstanceIdentifier<Node> PEER_IID = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId("test-topology")))
+ .child(Node.class, new NodeKey(
+ new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(NODE_ID)))
+ .build();
+ private final InstanceIdentifier<Node> SXP_NODE_IID = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId("sxp")))
+ .child(Node.class,
+ new NodeKey(
+ new org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId(
+ ADDR.getIpv4Address().getValue())))
+ .build();
+ private DataBroker dataBroker;
+ private IpSgtDistributionServiceImpl impl;
+ private SxpCapableNodeListener nodeListener;
+
+ @Before
+ public void init() throws Exception {
+ SxpControllerService sxpService = mock(SxpControllerService.class);
+ when(sxpService.addNode(any())).thenReturn(Futures.immediateFuture(
+ RpcResultBuilder.<AddNodeOutput>success(new AddNodeOutputBuilder().setResult(true).build()).build()));
+ nodeListener = PowerMockito.mock(SxpCapableNodeListener.class);
+ PowerMockito.whenNew(SxpCapableNodeListener.class).withAnyArguments().thenReturn(nodeListener);
+ dataBroker = mock(DataBroker.class);
+ impl = new IpSgtDistributionServiceImpl(dataBroker, sxpService, ADDR);
+ }
+
+ @Test
+ public void testInit() throws Exception {
+ RpcProviderRegistry rpcProvider = mock(RpcProviderRegistry.class);
+ SxpControllerService sxpService = mock(SxpControllerService.class);
+ when(rpcProvider.getRpcService(SxpControllerService.class)).thenReturn(sxpService);
+ when(sxpService.addNode(any())).thenReturn(Futures.immediateFuture(
+ RpcResultBuilder.<AddNodeOutput>success(new AddNodeOutputBuilder().setResult(true).build()).build()));
+ SxpCapableNodeListener nodeListener = PowerMockito.mock(SxpCapableNodeListener.class);
+ PowerMockito.whenNew(SxpCapableNodeListener.class).withAnyArguments().thenReturn(nodeListener);
+ impl = new IpSgtDistributionServiceImpl(dataBroker, sxpService, ADDR);
+ AddNodeInput addNodeInput = new AddNodeInputBuilder().setNodeId(new NodeId(ADDR.getIpv4Address().getValue()))
+ .setSourceIp(ADDR)
+ .setDescription(IpSgtDistributionServiceImpl.SXP_NODE_DESCRIPTION)
+ .build();
+ verify(sxpService).addNode(eq(addNodeInput));
+ PowerMockito.verifyNew(SxpCapableNodeListener.class);
+ }
+
+ @Test
+ public void testSendIpSgtBindingToPeer_successfullWrite() throws Exception {
+ SendIpSgtBindingToPeerInput input =
+ new SendIpSgtBindingToPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ WriteTransaction wtx = mock(WriteTransaction.class);
+ when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
+ when(wtx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(DOMAIN_ID);
+ Future<RpcResult<Void>> response = impl.sendIpSgtBindingToPeer(input);
+ new MasterDatabaseBindingBuilder().setIpPrefix(BINDING_ADDR).setSecurityGroupTag(BINDING_SGT).build();
+ verify(wtx).put(eq(LogicalDatastoreType.CONFIGURATION),
+ eq(InstanceIdentifier.builder(SXP_NODE_IID)
+ .augmentation(SxpNodeIdentity.class)
+ .child(SxpDomains.class)
+ .child(SxpDomain.class, new SxpDomainKey(DOMAIN_ID))
+ .child(MasterDatabase.class)
+ .child(MasterDatabaseBinding.class, new MasterDatabaseBindingKey(BINDING_ADDR))
+ .build()),
+ eq(new MasterDatabaseBindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSecurityGroupTag(BINDING_SGT)
+ .build()));
+ assertTrue(response.get().isSuccessful());
+ }
+
+ @Test
+ public void testSendIpSgtBindingToPeer_failedWrite() throws Exception {
+ SendIpSgtBindingToPeerInput input =
+ new SendIpSgtBindingToPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ WriteTransaction wtx = mock(WriteTransaction.class);
+ when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
+ when(wtx.submit()).thenReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("")));
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(DOMAIN_ID);
+ Future<RpcResult<Void>> response = impl.sendIpSgtBindingToPeer(input);
+ assertFalse(response.get().isSuccessful());
+ }
+
+ @Test
+ public void testSendIpSgtBindingToPeer_noSxpCapableNode() throws Exception {
+ SendIpSgtBindingToPeerInput input =
+ new SendIpSgtBindingToPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(null);
+ Future<RpcResult<Void>> response = impl.sendIpSgtBindingToPeer(input);
+ assertFalse(response.get().isSuccessful());
+ }
+
+ @Test
+ public void testRemoveIpSgtBindingFromPeer_successfullWrite() throws Exception {
+ RemoveIpSgtBindingFromPeerInput input =
+ new RemoveIpSgtBindingFromPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ WriteTransaction wtx = mock(WriteTransaction.class);
+ when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
+ when(wtx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(DOMAIN_ID);
+ Future<RpcResult<Void>> response = impl.removeIpSgtBindingFromPeer(input);
+ new MasterDatabaseBindingBuilder().setIpPrefix(BINDING_ADDR).setSecurityGroupTag(BINDING_SGT).build();
+ verify(wtx).delete(eq(LogicalDatastoreType.CONFIGURATION),
+ eq(InstanceIdentifier.builder(SXP_NODE_IID)
+ .augmentation(SxpNodeIdentity.class)
+ .child(SxpDomains.class)
+ .child(SxpDomain.class, new SxpDomainKey(DOMAIN_ID))
+ .child(MasterDatabase.class)
+ .child(MasterDatabaseBinding.class, new MasterDatabaseBindingKey(BINDING_ADDR))
+ .build()));
+ assertTrue(response.get().isSuccessful());
+ }
+
+ @Test
+ public void testRemoveIpSgtBindingFromPeer_failedWrite() throws Exception {
+ RemoveIpSgtBindingFromPeerInput input =
+ new RemoveIpSgtBindingFromPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ WriteTransaction wtx = mock(WriteTransaction.class);
+ when(dataBroker.newWriteOnlyTransaction()).thenReturn(wtx);
+ when(wtx.submit()).thenReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("")));
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(DOMAIN_ID);
+ Future<RpcResult<Void>> response = impl.removeIpSgtBindingFromPeer(input);
+ assertFalse(response.get().isSuccessful());
+ }
+
+ @Test
+ public void testRemoveIpSgtBindingFromPeer_noSxpCapableNode() throws Exception {
+ RemoveIpSgtBindingFromPeerInput input =
+ new RemoveIpSgtBindingFromPeerInputBuilder()
+ .setBinding(
+ Collections
+ .singletonList(new BindingBuilder().setIpPrefix(BINDING_ADDR)
+ .setSgt(BINDING_SGT)
+ .setPeerNode(Collections
+ .singletonList(new PeerNodeBuilder().setNodeIid(PEER_IID).build()))
+ .build()))
+ .build();
+ when(nodeListener.getDomainIdForPeer(PEER_IID)).thenReturn(null);
+ Future<RpcResult<Void>> response = impl.removeIpSgtBindingFromPeer(input);
+ assertFalse(response.get().isSuccessful());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.ip.sgt.distribution.service.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.groupbasedpolicy.test.CustomDataBrokerTest;
+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.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SxpConnectionAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.SxpConnectionAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.sxp.connection.fields.SxpConnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.ip.sgt.distribution.rev160715.sxp.connection.fields.SxpConnectionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.SxpNodeIdentityBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.SxpDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.network.topology.topology.node.sxp.domains.SxpDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.connections.fields.Connections;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.node.rev160308.sxp.connections.fields.connections.Connection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.protocol.rev141002.ConnectionMode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.CheckedFuture;
+
+public class SxpCapableNodeListenerTest extends CustomDataBrokerTest {
+
+ private final String SXP_NODE_ID = "sxp_node";
+ private final String NODE_ID = "node1";
+ private final IpAddress IP_ADDR = new IpAddress(new Ipv4Address("10.0.0.1"));
+ private final String PASSWD = "cisco123";
+ private final String TOPOLOGY_ID = "topology";
+ private final String DOMAIN_ID = TOPOLOGY_ID + "/" + NODE_ID;
+ private final PortNumber SXP_PORT = new PortNumber(64999);
+ private DataBroker dataBroker;
+ private SxpCapableNodeListener nodeListener;
+
+ @Override
+ public Collection<Class<?>> getClassesFromModules() {
+ return ImmutableList.of(Topology.class, SxpDomain.class, SxpConnectionAugmentation.class);
+ }
+
+ @Before
+ public void init() throws Exception {
+ dataBroker = getDataBroker();
+ nodeListener = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID);
+ }
+
+ @Test
+ public void testInit() throws Exception {
+ dataBroker = mock(DataBroker.class);
+ nodeListener = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID);
+ DataTreeIdentifier<SxpConnection> iid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class)
+ .child(Node.class)
+ .augmentation(SxpConnectionAugmentation.class)
+ .child(SxpConnection.class)
+ .build());
+ verify(dataBroker).registerDataTreeChangeListener(iid, nodeListener);
+ }
+
+ @Test
+ public void testClose() {
+ dataBroker = mock(DataBroker.class);
+ ListenerRegistration<SxpCapableNodeListener> registration = mock(ListenerRegistration.class);
+ when(dataBroker.registerDataTreeChangeListener(any(), isA(SxpCapableNodeListener.class)))
+ .thenReturn(registration);
+ nodeListener = new SxpCapableNodeListener(dataBroker, SXP_NODE_ID);
+ nodeListener.close();
+ verify(registration).close();
+ }
+
+ @Test
+ public void testOnDataTreeChange_createAndDeleteNode() throws Exception {
+ Node sxpNode =
+ new NodeBuilder().setNodeId(new NodeId(SXP_NODE_ID))
+ .addAugmentation(SxpNodeIdentity.class,
+ new SxpNodeIdentityBuilder().setSxpDomains(new SxpDomainsBuilder().build()).build())
+ .build();
+ InstanceIdentifier<Node> sxpNodeIid =
+ InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class,
+ new TopologyKey(new TopologyId(IpSgtDistributionServiceImpl.SXP_TOPOLOGY_ID)))
+ .child(Node.class, new NodeKey(new NodeId(SXP_NODE_ID)))
+ .build();
+ WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
+ wtx.put(LogicalDatastoreType.CONFIGURATION, sxpNodeIid, sxpNode, true);
+ Node node = new NodeBuilder().setNodeId(new NodeId(NODE_ID))
+ .addAugmentation(SxpConnectionAugmentation.class, new SxpConnectionAugmentationBuilder()
+ .setSxpConnection(new SxpConnectionBuilder().setIpAddress(IP_ADDR).setPassword(PASSWD).build()).build())
+ .build();
+ InstanceIdentifier<Node> nodeIid = InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class, new TopologyKey(new TopologyId(TOPOLOGY_ID)))
+ .child(Node.class, new NodeKey(new NodeId(NODE_ID)))
+ .build();
+ wtx.put(LogicalDatastoreType.CONFIGURATION, nodeIid, node, true);
+ wtx.submit().get();
+ assertEquals(DOMAIN_ID, nodeListener.getDomainIdForPeer(nodeIid));
+ InstanceIdentifier<SxpDomain> domainIid =
+ InstanceIdentifier.builder(NetworkTopology.class)
+ .child(Topology.class,
+ new TopologyKey(new TopologyId(IpSgtDistributionServiceImpl.SXP_TOPOLOGY_ID)))
+ .child(Node.class, new NodeKey(new NodeId(SXP_NODE_ID)))
+ .augmentation(SxpNodeIdentity.class)
+ .child(SxpDomains.class)
+ .child(SxpDomain.class, new SxpDomainKey(DOMAIN_ID))
+ .build();
+ ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction();
+ CheckedFuture<Optional<SxpDomain>, ReadFailedException> read =
+ rtx.read(LogicalDatastoreType.CONFIGURATION, domainIid);
+ Optional<SxpDomain> optionalDomain = read.get();
+ assertTrue(optionalDomain.isPresent());
+ SxpDomain sxpDomain = optionalDomain.get();
+ Connections connections = sxpDomain.getConnections();
+ assertNotNull(connections);
+ List<Connection> connectionList = connections.getConnection();
+ assertNotNull(connectionList);
+ assertEquals(1, connectionList.size());
+ Connection connection = connectionList.get(0);
+ assertEquals(IP_ADDR, connection.getPeerAddress());
+ assertEquals(PASSWD, connection.getPassword());
+ assertEquals(SXP_PORT, connection.getTcpPort());
+ assertEquals(ConnectionMode.Speaker, connection.getMode());
+
+ wtx = dataBroker.newWriteOnlyTransaction();
+ wtx.delete(LogicalDatastoreType.CONFIGURATION, nodeIid);
+ wtx.submit().get();
+ assertNull(nodeListener.getDomainIdForPeer(nodeIid));
+ rtx = dataBroker.newReadOnlyTransaction();
+ read = rtx.read(LogicalDatastoreType.CONFIGURATION, domainIid);
+ assertFalse(read.get().isPresent());
+ }
+}
<module>distribution-karaf</module>
<module>features</module>
<module>sxp-integration</module>
+ <module>ip-sgt-distribution-service</module>
</modules>
<build>