Introduced neutron-mapper 72/17272/41
authorMartin Sunal <msunal@cisco.com>
Sat, 28 Mar 2015 04:01:53 +0000 (05:01 +0100)
committerMartin Sunal <msunal@cisco.com>
Tue, 14 Apr 2015 07:03:24 +0000 (09:03 +0200)
- dependecy on ODL neutron-northbound service
- Mapping between neutron and GBP entities:
  - neutron network to gbp l2-flood-domain mapping
    l2-bridge-domain is generated as a parent of l2-flood-domain
    l3-context is generated as a parent of l2-bridge-domain
  - neutron subnet to gbp subnet mapping
    l2-flood domain is set as a parent of subnet
  - neutron port to gbp endpoint mapping
    endpoint is registered
    endpoint-l3 is registered if a port contains fixed-ips
  - neutron security group with security group rules to endpoint group pairs with contract

Change-Id: I1fea5cb67ebd7d080cf244ecc2b1da5072efd181
Signed-off-by: Martin Sunal <msunal@cisco.com>
25 files changed:
commons/parent/pom.xml
features/pom.xml
features/src/main/resources/features.xml
neutron-mapper-config/pom.xml [new file with mode: 0644]
neutron-mapper-config/src/main/resources/initial/15-neutron-mapper.xml [new file with mode: 0644]
neutron-mapper/pom.xml [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModule.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModuleFactory.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/NeutronMapper.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronNetworkAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronRouterAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityGroupAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityRuleAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSubnetAware.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/StatusCode.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/TransformSecRule.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/DataStoreHelper.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/IidFactory.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/MappingUtils.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/NeutronUtils.java [new file with mode: 0644]
neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/Utils.java [new file with mode: 0644]
neutron-mapper/src/main/yang/mapper.yang [new file with mode: 0644]
neutron-mapper/src/main/yang/neutron-mapper-impl.yang [new file with mode: 0644]
pom.xml

index f48dadef74265211364e84b2c6838350088ef98b..54558fca373b63ba16ef23f09b43cababa1dac14 100644 (file)
     <openflowplugin.distribution.version>0.1.0-SNAPSHOT</openflowplugin.distribution.version>
     <openflowplugin-nicira.version>0.1.0-SNAPSHOT</openflowplugin-nicira.version>
     <openflowjava.distribution.version>0.6.0-SNAPSHOT</openflowjava.distribution.version>
+    <neutron.version>0.5.0-SNAPSHOT</neutron.version>
     <restconf.project.version>1.2.0-SNAPSHOT</restconf.project.version>
     <config.configfile.directory>etc/opendaylight/karaf</config.configfile.directory>
     <groupbasedpolicy.project.version>0.2.0-SNAPSHOT</groupbasedpolicy.project.version>
     <config.groupbasedpolicy.ofoverlayconfigfile>15-groupbasedpolicy-ofoverlay.xml</config.groupbasedpolicy.ofoverlayconfigfile>
     <config.groupbasedpolicy.opflexconfigfile>15-groupbasedpolicy-opflex.xml</config.groupbasedpolicy.opflexconfigfile>
     <config.groupbasedpolicy.openstackendpointconfigfile>15-groupbasedpolicy-openstackendpoint.xml</config.groupbasedpolicy.openstackendpointconfigfile>
+    <config.groupbasedpolicy.neutronmapperconfigfile>15-neutron-mapper.xml</config.groupbasedpolicy.neutronmapperconfigfile>
     <karaf.version>3.0.1</karaf.version>
     <exam.version>4.4.0</exam.version> <!-- Needs to remain exported, as its used for dependencies, too -->
     <sfc.version>0.1.0-SNAPSHOT</sfc.version>
index 0fdd10865867bb880eb823eae56158e22b38f66f..fccd52e1342e4d0a2fbc6425b8a2ad4e835ff061 100644 (file)
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>features-neutron</artifactId>
+      <classifier>features</classifier>
+      <version>${neutron.version}</version>
+      <type>xml</type>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>groupbasedpolicy</artifactId>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>neutron-mapper-config</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
    <!-- dependency for opendaylight-karaf-empty for use by testing -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
index 776244351b745297605df2543a24bb7587f54e25..6f1122a60765d7c7263934ced2adda08dd398334 100644 (file)
@@ -19,6 +19,9 @@
     <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.distribution.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/${openflowplugin.distribution.version}/xml/features</repository>
 
+    <!-- Repos needed by the Neutron Mapper -->
+    <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
+
     <!-- The common GBP components -->
     <feature name='odl-groupbasedpolicy-base' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: Base Copmonents'>
         <feature version="${mdsal.version}">odl-mdsal-broker</feature>
         <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.openstackendpointconfigfile}">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-openstackendpoint-config/${project.version}/xml/config</configfile>
     </feature>
 
+
+    <!--
+         The Neutron provider
+    -->
+    <feature name='odl-groupbasedpolicy-neutronmapper' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: Neutron Mapper mapps neutron APIs to GBP APIs '>
+        <feature version="${mdsal.version}">odl-mdsal-broker</feature>
+        <feature version="${neutron.version}">odl-neutron-service</feature>
+        <feature version="${project.version}">odl-groupbasedpolicy-base</feature>
+        <feature version="${project.version}">odl-groupbasedpolicy-ofoverlay</feature>
+        <bundle>mvn:org.opendaylight.groupbasedpolicy/neutron-mapper/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.groupbasedpolicy.neutronmapperconfigfile}">mvn:org.opendaylight.groupbasedpolicy/neutron-mapper-config/${project.version}/xml/config</configfile>
+    </feature>
 </features>
 
diff --git a/neutron-mapper-config/pom.xml b/neutron-mapper-config/pom.xml
new file mode 100644 (file)
index 0000000..1ed430f
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2014 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.groupbasedpolicy</groupId>
+      <artifactId>commons.groupbasedpolicy</artifactId>
+      <version>0.2.0-SNAPSHOT</version>
+      <relativePath>../commons/parent</relativePath>
+    </parent>
+
+    <artifactId>neutron-mapper-config</artifactId>
+    <description>Controller Configuration files for neutron-mapper</description>
+    <packaging>jar</packaging>
+    <build>
+      <plugins>
+          <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>build-helper-maven-plugin</artifactId>
+          <executions>
+            <execution>
+              <id>attach-artifacts</id>
+              <goals>
+                <goal>attach-artifact</goal>
+              </goals>
+              <phase>package</phase>
+              <configuration>
+                <artifacts>
+                  <artifact>
+                    <file>${project.build.directory}/classes/initial/15-neutron-mapper.xml</file>
+                    <type>xml</type>
+                    <classifier>config</classifier>
+                  </artifact>
+                </artifacts>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </build>
+</project>
diff --git a/neutron-mapper-config/src/main/resources/initial/15-neutron-mapper.xml b/neutron-mapper-config/src/main/resources/initial/15-neutron-mapper.xml
new file mode 100644 (file)
index 0000000..2ba6576
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2014 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:neutron-mapper="urn:opendaylight:params:xml:ns:yang:controller:config:neutron-mapper:impl">
+                        neutron-mapper:neutron-mapper-impl
+                    </type>
+                    <name>neutron-mapper-impl</name>
+
+                    <rpc-registry>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                        <name>binding-rpc-broker</name>
+                    </rpc-registry>
+
+                    <data-broker>
+                      <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+                      <name>binding-data-broker</name>
+                    </data-broker>
+                </module>
+            </modules>
+        </data>
+
+    </configuration>
+
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:neutron-mapper:impl?module=neutron-mapper-impl&amp;revision=2015-02-19</capability>
+    </required-capabilities>
+
+</snapshot>
diff --git a/neutron-mapper/pom.xml b/neutron-mapper/pom.xml
new file mode 100644 (file)
index 0000000..0921f0c
--- /dev/null
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (c) 2014 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
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.groupbasedpolicy</groupId>
+        <artifactId>groupbasedpolicy.project</artifactId>
+        <version>0.2.0-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+    <artifactId>neutron-mapper</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>groupbasedpolicy</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ofoverlay-renderer</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.neutron</groupId>
+            <artifactId>neutron-spi</artifactId>
+            <version>0.5.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package></Export-Package>
+                        <Import-Package>*</Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                    <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${project.build.directory}/generated-sources/sal</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>0.3.0-SNAPSHOT</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <phase>generate-sources</phase>
+                        <configuration>
+                            <sources>
+                                <source>target/generated-sources/sal</source>
+                                <source>target/generated-sources/config</source>
+                                <source>target/generated-resources/</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModule.java b/neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModule.java
new file mode 100644 (file)
index 0000000..e48646b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 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.neutron_mapper.impl;
+
+import org.opendaylight.groupbasedpolicy.neutron.mapper.NeutronMapper;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NeutronMapperModule extends org.opendaylight.controller.config.yang.config.neutron_mapper.impl.AbstractNeutronMapperModule {
+
+    private final Logger LOG = LoggerFactory.getLogger(NeutronMapperModule.class);
+    private BundleContext bundleContext;
+
+    public NeutronMapperModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public NeutronMapperModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.neutron_mapper.impl.NeutronMapperModule 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() {
+        final NeutronMapper neutronMapper = new NeutronMapper(getDataBrokerDependency(), getRpcRegistryDependency(), bundleContext);
+        LOG.info("Neutron mapper started.");
+        return new AutoCloseable() {
+
+            @Override
+            public void close() throws Exception {
+                neutronMapper.close();
+            }
+        };
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModuleFactory.java b/neutron-mapper/src/main/java/org/opendaylight/controller/config/yang/config/neutron_mapper/impl/NeutronMapperModuleFactory.java
new file mode 100644 (file)
index 0000000..e1fc85e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: neutron-mapper-impl yang module local name: neutron-mapper-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Feb 19 12:58:22 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+/*
+ * Copyright (c) 2014 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.neutron_mapper.impl;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+public class NeutronMapperModuleFactory extends org.opendaylight.controller.config.yang.config.neutron_mapper.impl.AbstractNeutronMapperModuleFactory {
+
+    /**
+     * @see org.opendaylight.controller.config.yang.config.neutron_mapper.impl.AbstractNeutronMapperModuleFactory#createModule(java.lang.String, org.opendaylight.controller.config.api.DependencyResolver, org.osgi.framework.BundleContext)
+     */
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        NeutronMapperModule module = (NeutronMapperModule) super.createModule(instanceName, dependencyResolver, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+    /**
+     * @see org.opendaylight.controller.config.yang.config.neutron_mapper.impl.AbstractNeutronMapperModuleFactory#createModule(java.lang.String, org.opendaylight.controller.config.api.DependencyResolver, org.opendaylight.controller.config.api.DynamicMBeanWithInstance, org.osgi.framework.BundleContext)
+     */
+    @Override
+    public Module createModule(String instanceName, DependencyResolver dependencyResolver, DynamicMBeanWithInstance old,
+            BundleContext bundleContext) throws Exception {
+        NeutronMapperModule module = (NeutronMapperModule) super.createModule(instanceName, dependencyResolver, old, bundleContext);
+        module.setBundleContext(bundleContext);
+        return module;
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/NeutronMapper.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/NeutronMapper.java
new file mode 100644 (file)
index 0000000..7306a04
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 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.neutron.mapper;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronNetworkAware;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronPortAware;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSecurityGroupAware;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSubnetAware;
+import org.opendaylight.neutron.spi.INeutronNetworkAware;
+import org.opendaylight.neutron.spi.INeutronPortAware;
+import org.opendaylight.neutron.spi.INeutronSecurityGroupAware;
+import org.opendaylight.neutron.spi.INeutronSubnetAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class NeutronMapper implements AutoCloseable {
+
+    private final List<ServiceRegistration<?>> registrations = new ArrayList<ServiceRegistration<?>>();
+
+    public NeutronMapper(DataBroker dataProvider, RpcProviderRegistry rpcProvider, BundleContext context) {
+        checkNotNull(dataProvider);
+        checkNotNull(rpcProvider);
+        checkNotNull(context);
+        EndpointService epService = rpcProvider.getRpcService(EndpointService.class);
+
+        registerAwareProviders(dataProvider, epService, context);
+    }
+
+    private void registerAwareProviders(DataBroker dataProvider, EndpointService epService, BundleContext context) {
+        ServiceRegistration<INeutronNetworkAware> neutronNetworkAwareRegistration = context.registerService(
+            INeutronNetworkAware.class, new NeutronNetworkAware(dataProvider), null);
+        registrations.add(neutronNetworkAwareRegistration);
+
+        ServiceRegistration<INeutronSubnetAware> neutronSubnetAwareRegistration = context.registerService(
+            INeutronSubnetAware.class, new NeutronSubnetAware(dataProvider), null);
+        registrations.add(neutronSubnetAwareRegistration);
+
+        ServiceRegistration<INeutronPortAware> neutronPortAwareRegistration = context.registerService(
+            INeutronPortAware.class, new NeutronPortAware(dataProvider, epService), null);
+        registrations.add(neutronPortAwareRegistration);
+
+        ServiceRegistration<INeutronSecurityGroupAware> neutronSecurityGroupAwareRegistration = context.registerService(
+            INeutronSecurityGroupAware.class, new NeutronSecurityGroupAware(dataProvider), null);
+        registrations.add(neutronSecurityGroupAwareRegistration);
+    }
+
+    /**
+     * @see java.lang.AutoCloseable#close()
+     */
+    @Override
+    public void close() throws Exception {
+        for (ServiceRegistration<?> registration : registrations) {
+            registration.unregister();
+        }
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronNetworkAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronNetworkAware.java
new file mode 100644 (file)
index 0000000..e59e2bd
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015 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.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.UUID;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.neutron.spi.INeutronNetworkAware;
+import org.opendaylight.neutron.spi.NeutronNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class NeutronNetworkAware implements INeutronNetworkAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkAware.class);
+    private final DataBroker dataProvider;
+
+    public NeutronNetworkAware(DataBroker dataProvider) {
+        this.dataProvider = checkNotNull(dataProvider);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canCreateNetwork(org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public int canCreateNetwork(NeutronNetwork network) {
+        LOG.trace("canCreateNetwork - {}", network);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkCreated(org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public void neutronNetworkCreated(NeutronNetwork network) {
+        LOG.trace("neutronNetworkCreated - {}", network);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        L2FloodDomainId l2FdId = new L2FloodDomainId(network.getID());
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(network.getTenantID()));
+        addEpgDhcpIfMissing(tenantId, rwTx);
+        addEpgRouterIfMissing(tenantId, rwTx);
+        Description domainDescription = new Description(MappingUtils.NEUTRON_NETWORK__ + network.getID());
+        Name name = null;
+        if (network.getNetworkName() != null) {
+            name = new Name(network.getNetworkName());
+        }
+        L3ContextId l3ContextId = new L3ContextId(UUID.randomUUID().toString());
+        L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
+            .setDescription(domainDescription)
+            .setName(name)
+            .build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l3ContextIid(tenantId, l3ContextId), l3Context, true);
+
+        L2BridgeDomainId l2BdId = new L2BridgeDomainId(UUID.randomUUID().toString());
+        L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId)
+            .setParent(l3ContextId)
+            .setDescription(domainDescription)
+            .setName(name)
+            .build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
+
+        L2FloodDomain l2Fd = new L2FloodDomainBuilder().setId(l2FdId)
+            .setParent(l2BdId)
+            .setDescription(domainDescription)
+            .setName(name)
+            .build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2FloodDomainIid(tenantId, l2FdId), l2Fd, true);
+
+        NetworkMapping networkMapping = new NetworkMappingBuilder().setNetworkId(l2FdId)
+            .setL2BridgeDomainId(l2BdId)
+            .setL3ContextId(l3ContextId)
+            .build();
+        rwTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.networkMappingIid(l2FdId), networkMapping, true);
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    private void addEpgDhcpIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
+        InstanceIdentifier<EndpointGroup> epgDhcpIid = IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_DHCP_ID);
+        Optional<EndpointGroup> potentialDhcpEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                epgDhcpIid, rwTx);
+        if (!potentialDhcpEpg.isPresent()) {
+            EndpointGroup epgDhcp = new EndpointGroupBuilder().setId(MappingUtils.EPG_DHCP_ID)
+                .setName(new Name("DHCP_group"))
+                .setDescription(new Description("Group where are all DHCP endpoints."))
+                .build();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, epgDhcpIid, epgDhcp);
+        }
+    }
+
+    private void addEpgRouterIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
+        Optional<EndpointGroup> potentialEpgRouter = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
+        if (potentialEpgRouter.isPresent()) {
+            EndpointGroup epgRouter = new EndpointGroupBuilder().setId(MappingUtils.EPG_ROUTER_ID)
+                .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + "epg_routers"))
+                .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
+                .build();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), epgRouter);
+        }
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canUpdateNetwork(org.opendaylight.neutron.spi.NeutronNetwork,
+     *      org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public int canUpdateNetwork(NeutronNetwork delta, NeutronNetwork original) {
+        LOG.trace("canUpdateNetwork - delta: {} original: {}", delta, original);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkUpdated(org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public void neutronNetworkUpdated(NeutronNetwork network) {
+        LOG.trace("neutronNetworkUpdated - {}", network);
+        // TODO we could update just name
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canDeleteNetwork(org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public int canDeleteNetwork(NeutronNetwork network) {
+        LOG.trace("canDeleteNetwork - {}", network);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkDeleted(org.opendaylight.neutron.spi.NeutronNetwork)
+     */
+    @Override
+    public void neutronNetworkDeleted(NeutronNetwork network) {
+        LOG.trace("neutronNetworkDeleted - {}", network);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(network.getTenantID()));
+        L2FloodDomainId l2FdId = new L2FloodDomainId(network.getID());
+        Optional<NetworkMapping> potentionalNetworkMapping = DataStoreHelper.readFromDs(
+                LogicalDatastoreType.OPERATIONAL, IidFactory.networkMappingIid(l2FdId), rwTx);
+        if (!potentionalNetworkMapping.isPresent()) {
+            LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        NetworkMapping networkMapping = potentionalNetworkMapping.get();
+        L2BridgeDomainId l2BdId = networkMapping.getL2BridgeDomainId();
+        L3ContextId l3ContextId = networkMapping.getL3ContextId();
+        if (l2BdId == null || l3ContextId == null) {
+            LOG.warn("Illegal state - network-mapping {} is not valid.", networkMapping);
+            rwTx.cancel();
+            return;
+        }
+
+        Optional<L2FloodDomain> potentialL2Fd = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l2FloodDomainIid(tenantId, l2FdId), rwTx);
+        if (!potentialL2Fd.isPresent()) {
+            LOG.warn("Illegal state - l2-flood-domain {} does not exist.", l2FdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        Optional<L2BridgeDomain> potentialL2Bd = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
+        if (!potentialL2Bd.isPresent()) {
+            LOG.warn("Illegal state - l2-bridge-domain {} does not exist.", l2BdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        Optional<L3Context> potentialL3Context = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
+        if (!potentialL3Context.isPresent()) {
+            LOG.warn("Illegal state - l3-context {} does not exist.", l3ContextId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronPortAware.java
new file mode 100644 (file)
index 0000000..95945a6
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2015 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.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
+import org.opendaylight.neutron.spi.INeutronPortAware;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+
+public class NeutronPortAware implements INeutronPortAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
+    private static final String DEVICE_OWNER_DHCP = "network:dhcp";
+    private static final String DEVICE_OWNER_ROUTER_IFACE = "network:router_interface";
+    private static final int DHCP_CLIENT_PORT = 68;
+    private static final int DHCP_SERVER_PORT = 67;
+    private final DataBroker dataProvider;
+    private final EndpointService epService;
+
+    public NeutronPortAware(DataBroker dataProvider, EndpointService epService) {
+        this.dataProvider = checkNotNull(dataProvider);
+        this.epService = checkNotNull(epService);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#canCreatePort(org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public int canCreatePort(NeutronPort port) {
+        LOG.trace("canCreatePort - {}", port);
+        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
+        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
+        if (fixedIPs != null && fixedIPs.size() > 1) {
+            LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
+            return StatusCode.BAD_REQUEST;
+        }
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortCreated(org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public void neutronPortCreated(NeutronPort port) {
+        LOG.trace("neutronPortCreated - {}", port);
+        if (isRouterInterfacePort(port)) {
+            LOG.trace("Port is router interface - do nothing - NeutronRouterAware handles router iface");
+            return;
+        }
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+
+        if (isDhcpPort(port)) {
+            List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, null, rwTx);
+            if (dhcpSecRules == null) {
+                rwTx.cancel();
+                return;
+            }
+
+            for (NeutronSecurityRule dhcpSecRule : dhcpSecRules) {
+                boolean isDhcpSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(dhcpSecRule, rwTx);
+                if (!isDhcpSecRuleAdded) {
+                    rwTx.cancel();
+                    return;
+                }
+            }
+        } else {
+            List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
+            if (secGroups != null) {
+                for (NeutronSecurityGroup secGroup : secGroups) {
+                    EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
+                    Optional<EndpointGroup> potentialEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                            IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
+                    if (!potentialEpg.isPresent()) {
+                        boolean isSecGroupCreated = NeutronSecurityGroupAware.addNeutronSecurityGroup(secGroup, rwTx);
+                        if (!isSecGroupCreated) {
+                            rwTx.cancel();
+                            return;
+                        }
+                        if (containsSecRuleWithRemoteSecGroup(secGroup)) {
+                            List<NeutronSecurityRule> dhcpSecRules = createDhcpSecRules(port, epgId, rwTx);
+                            if (dhcpSecRules == null) {
+                                rwTx.cancel();
+                                return;
+                            }
+                            List<NeutronSecurityRule> routerSecRules = NeutronRouterAware.createRouterSecRules(port, epgId, rwTx);
+                            if (routerSecRules == null) {
+                                rwTx.cancel();
+                                return;
+                            }
+                        }
+                    } else {
+                        List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
+                        if (secRules != null) {
+                            for (NeutronSecurityRule secRule : secRules) {
+                                NeutronSecurityRuleAware.addNeutronSecurityRule(secRule, rwTx);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        boolean isNeutronPortCreated = addNeutronPort(port, rwTx, epService);
+        if (!isNeutronPortCreated) {
+            rwTx.cancel();
+            return;
+        }
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    public static boolean addNeutronPort(NeutronPort port, ReadWriteTransaction rwTx, EndpointService epService) {
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
+        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
+        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
+        if (!isFwCtxValid) {
+            return false;
+        }
+
+        try {
+            RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
+            RpcResult<Void> rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
+            if (!rpcResult.isSuccessful()) {
+                LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
+                return false;
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("addPort - RPC invocation failed.", e);
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean validateForwardingCtx(ForwardingCtx fwCtx) {
+        if (fwCtx.getL2FloodDomain() == null) {
+            LOG.warn("Illegal state - l2-flood-domain does not exist.");
+            return false;
+        }
+        if (fwCtx.getL2BridgeDomain() == null) {
+            LOG.warn("Illegal state - l2-bridge-domain does not exist.");
+            return false;
+        }
+        if (fwCtx.getL3Context() == null) {
+            LOG.warn("Illegal state - l3-context does not exist.");
+            return false;
+        }
+        return true;
+    }
+
+    private List<NeutronSecurityRule> createDhcpSecRules(NeutronPort port, EndpointGroupId consumerEpgId, ReadTransaction rTx) {
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+        Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
+        if (firstIp == null) {
+            LOG.warn("Illegal state - DHCP port does not have an IP address.");
+            return null;
+        }
+        SubnetId dhcpSubnetId = new SubnetId(firstIp.getSubnetUUID());
+        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.subnetIid(tenantId, dhcpSubnetId), rTx);
+        if (!potentialSubnet.isPresent()) {
+            LOG.warn("Illegal state - Subnet {} where is DHCP port does not exist.", dhcpSubnetId.getValue());
+            return null;
+        }
+        IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
+        NeutronSecurityRule dhcpRuleEgress = createDhcpSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId, true);
+        NeutronSecurityRule dhcpRuleIngress = createDhcpSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId, false);
+        return ImmutableList.of(dhcpRuleEgress, dhcpRuleIngress);
+    }
+
+    private NeutronSecurityRule createDhcpSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet, EndpointGroupId consumerEpgId,
+            boolean isEgress) {
+        NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
+        dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_DHCP_ID.getValue());
+        dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
+        dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
+        if (consumerEpgId != null) {
+            dhcpSecRule.setSecurityRemoteGroupID(consumerEpgId.getValue());
+        }
+        if (isEgress) {
+            dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
+            dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
+            dhcpSecRule.setSecurityRulePortMin(DHCP_CLIENT_PORT);
+            dhcpSecRule.setSecurityRulePortMax(DHCP_CLIENT_PORT);
+        } else {
+            dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
+            dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
+            dhcpSecRule.setSecurityRulePortMin(DHCP_SERVER_PORT);
+            dhcpSecRule.setSecurityRulePortMax(DHCP_SERVER_PORT);
+        }
+        dhcpSecRule.setSecurityRuleProtocol(NeutronUtils.UDP);
+        if (ipSubnet.getIpv4Prefix() != null) {
+            dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
+        } else {
+            dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
+        }
+        return dhcpSecRule;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#canUpdatePort(org.opendaylight.neutron.spi.NeutronPort,
+     *      org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public int canUpdatePort(NeutronPort delta, NeutronPort original) {
+        LOG.trace("canUpdatePort - delta: {} original: {}", delta, original);
+        if (delta.getFixedIPs() == null || delta.getFixedIPs().isEmpty()) {
+            return StatusCode.OK;
+        }
+        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
+        List<Neutron_IPs> fixedIPs = delta.getFixedIPs();
+        if (fixedIPs != null && fixedIPs.size() > 1) {
+            LOG.warn("Neutron mapper does not support multiple IPs on the same port.");
+            return StatusCode.BAD_REQUEST;
+        }
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortUpdated(org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public void neutronPortUpdated(NeutronPort port) {
+        LOG.trace("neutronPortUpdated - {}", port);
+        if (isRouterInterfacePort(port)) {
+            LOG.trace("Port is router interface - do nothing - NeutronRouterAware handles router iface");
+            return;
+        }
+        ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+        MacAddress macAddress = new MacAddress(port.getMacAddress());
+        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
+        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
+        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
+        if (!isFwCtxValid) {
+            rTx.close();
+            return;
+        }
+
+        Optional<Endpoint> potentionalEp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
+                IidFactory.endpointIid(fwCtx.getL2BridgeDomain().getId(), macAddress), rTx);
+        if (!potentionalEp.isPresent()) {
+            LOG.warn("Illegal state - endpoint {} does not exist.", new EndpointKey(fwCtx.getL2BridgeDomain().getId(),
+                    macAddress));
+            rTx.close();
+            return;
+        }
+
+        Endpoint ep = potentionalEp.get();
+        if (isEpIpDifferentThanPortFixedIp(ep, port) || isEpgDifferentThanSecGrp(ep, port)) {
+            UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(ep);
+            RegisterEndpointInput registerEpRpcInput = createRegisterEndpointInput(port, fwCtx);
+            try {
+                RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
+                if (!rpcResult.isSuccessful()) {
+                    LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
+                    rTx.close();
+                    return;
+                }
+                rpcResult = epService.registerEndpoint(registerEpRpcInput).get();
+                if (!rpcResult.isSuccessful()) {
+                    LOG.warn("Illegal state - RPC registerEndpoint failed. Input of RPC: {}", registerEpRpcInput);
+                    rTx.close();
+                    return;
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.error("addPort - RPC invocation failed.", e);
+                rTx.close();
+                return;
+            }
+        }
+        rTx.close();
+    }
+
+    private boolean isEpIpDifferentThanPortFixedIp(Endpoint ep, NeutronPort port) {
+        List<L3Address> l3Addresses = ep.getL3Address();
+        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
+        if ((l3Addresses == null || l3Addresses.isEmpty()) && (fixedIPs == null || fixedIPs.isEmpty())) {
+            return false;
+        }
+        if (l3Addresses != null && !l3Addresses.isEmpty() && fixedIPs != null && !fixedIPs.isEmpty()) {
+            if (fixedIPs.get(0).getIpAddress().equals(Utils.getStringIpAddress(l3Addresses.get(0).getIpAddress()))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean isEpgDifferentThanSecGrp(Endpoint ep, NeutronPort port) {
+        List<EndpointGroupId> epgIds = ep.getEndpointGroups();
+        List<NeutronSecurityGroup> secGroups = port.getSecurityGroups();
+        if ((epgIds == null || epgIds.isEmpty()) && (secGroups == null || secGroups.isEmpty())) {
+            return false;
+        }
+        if (epgIds != null && !epgIds.isEmpty() && secGroups != null && !secGroups.isEmpty()) {
+            if (epgIds.size() != secGroups.size()) {
+                return true;
+            }
+            Collection<EndpointGroupId> epgIdsFromSecGroups = Collections2.transform(secGroups,
+                    new Function<NeutronSecurityGroup, EndpointGroupId>() {
+
+                        @Override
+                        public EndpointGroupId apply(NeutronSecurityGroup input) {
+                            return new EndpointGroupId(input.getSecurityGroupUUID());
+                        }
+                    });
+            // order independent equals
+            Set<EndpointGroupId> one = new HashSet<>(epgIds);
+            Set<EndpointGroupId> two = new HashSet<>(epgIdsFromSecGroups);
+            if (one.equals(two)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#canDeletePort(org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public int canDeletePort(NeutronPort port) {
+        LOG.trace("canDeletePort - {}", port);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronPortAware#neutronPortDeleted(org.opendaylight.neutron.spi.NeutronPort)
+     */
+    @Override
+    public void neutronPortDeleted(NeutronPort port) {
+        LOG.trace("neutronPortDeleted - {}", port);
+        if (isRouterInterfacePort(port)) {
+            LOG.trace("Port is router interface - do nothing - NeutronRouterAware handles router iface");
+            return;
+        }
+        ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+        L2FloodDomainId l2FdId = new L2FloodDomainId(port.getNetworkUUID());
+        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
+        boolean isFwCtxValid = validateForwardingCtx(fwCtx);
+        if (!isFwCtxValid) {
+            rTx.close();
+            return;
+        }
+
+        UnregisterEndpointInput unregisterEpRpcInput = createUnregisterEndpointInput(port, fwCtx);
+        try {
+            RpcResult<Void> rpcResult = epService.unregisterEndpoint(unregisterEpRpcInput).get();
+            if (!rpcResult.isSuccessful()) {
+                LOG.warn("Illegal state - RPC unregisterEndpoint failed. Input of RPC: {}", unregisterEpRpcInput);
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("addPort - RPC invocation failed.", e);
+        } finally {
+            rTx.close();
+        }
+    }
+
+    private static RegisterEndpointInput createRegisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
+        List<EndpointGroupId> epgIds = new ArrayList<>();
+        // each EP has to be in EPG ANY, except dhcp and router
+        if (isDhcpPort(port)) {
+            epgIds.add(MappingUtils.EPG_DHCP_ID);
+        } else if (isRouterInterfacePort(port)) {
+            epgIds.add(MappingUtils.EPG_ROUTER_ID);
+        } else if (!containsSecRuleWithRemoteSecGroup(port.getSecurityGroups())) {
+            epgIds.add(MappingUtils.EPG_ANY_ID);
+        }
+
+        List<NeutronSecurityGroup> securityGroups = port.getSecurityGroups();
+        if ((securityGroups == null || securityGroups.isEmpty())) {
+            if (!isDhcpPort(port) && !isRouterInterfacePort(port)) {
+                LOG.warn(
+                        "Port {} does not contain any security group. The port should belong to 'default' security group at least.",
+                        port.getPortUUID());
+            }
+        } else {
+            for (NeutronSecurityGroup secGrp : securityGroups) {
+                epgIds.add(new EndpointGroupId(secGrp.getSecurityGroupUUID()));
+            }
+        }
+        RegisterEndpointInputBuilder inputBuilder = new RegisterEndpointInputBuilder().setL2Context(
+                fwCtx.getL2BridgeDomain().getId())
+            .setMacAddress(new MacAddress(port.getMacAddress()))
+            .setTenant(new TenantId(Utils.normalizeUuid(port.getTenantID())))
+            .setEndpointGroups(epgIds)
+            .addAugmentation(OfOverlayContextInput.class,
+                    new OfOverlayContextInputBuilder().setPortName(createTapPortName(port)).build())
+            .setTimestamp(System.currentTimeMillis());
+        List<Neutron_IPs> fixedIPs = port.getFixedIPs();
+        // TODO Li msunal this getting of just first IP has to be rewrite when OFOverlay renderer
+        // will support l3-endpoints. Then we will register L2 and L3 endpoints separately.
+        Neutron_IPs firstIp = getFirstIp(fixedIPs);
+        if (firstIp != null) {
+            inputBuilder.setNetworkContainment(new SubnetId(firstIp.getSubnetUUID()));
+            L3Address l3Address = new L3AddressBuilder().setIpAddress(Utils.createIpAddress(firstIp.getIpAddress()))
+                .setL3Context(fwCtx.getL3Context().getId())
+                .build();
+            inputBuilder.setL3Address(ImmutableList.of(l3Address));
+        }
+        if (!Strings.isNullOrEmpty(port.getName())) {
+
+        }
+        return inputBuilder.build();
+    }
+
+    private static boolean containsSecRuleWithRemoteSecGroup(List<NeutronSecurityGroup> secGroups) {
+        if (secGroups == null) {
+            return false;
+        }
+        for (NeutronSecurityGroup secGroup : secGroups) {
+            boolean containsSecRuleWithRemoteSecGroup = containsSecRuleWithRemoteSecGroup(secGroup);
+            if (containsSecRuleWithRemoteSecGroup) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean containsSecRuleWithRemoteSecGroup(NeutronSecurityGroup secGroup) {
+        List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
+        if (secRules == null) {
+            return false;
+        }
+        for (NeutronSecurityRule secRule : secRules) {
+            if (!Strings.isNullOrEmpty(secRule.getSecurityRemoteGroupID())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static Name createTapPortName(NeutronPort port) {
+        return new Name("tap" + port.getID().substring(0, 11));
+    }
+
+    private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
+        if (fixedIPs == null || fixedIPs.isEmpty()) {
+            return null;
+        }
+        Neutron_IPs neutron_Ip = fixedIPs.get(0);
+        if (fixedIPs.size() > 1) {
+            LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
+                    neutron_Ip);
+        }
+        return neutron_Ip;
+    }
+
+    private static boolean isDhcpPort(NeutronPort port) {
+        return DEVICE_OWNER_DHCP.equals(port.getDeviceOwner());
+    }
+
+    private static boolean isRouterInterfacePort(NeutronPort port) {
+        return DEVICE_OWNER_ROUTER_IFACE.equals(port.getDeviceOwner());
+    }
+
+    private UnregisterEndpointInput createUnregisterEndpointInput(Endpoint ep) {
+        UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
+        L2 l2Ep = new L2Builder().setL2Context(ep.getL2Context()).setMacAddress(ep.getMacAddress()).build();
+        inputBuilder.setL2(ImmutableList.of(l2Ep));
+        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
+        // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
+        // be registered separately.
+        if (ep.getL3Address() != null && !ep.getL3Address().isEmpty()) {
+            List<L3> l3Eps = new ArrayList<>();
+            for (L3Address ip : ep.getL3Address()) {
+                l3Eps.add(new L3Builder().setL3Context(ip.getL3Context()).setIpAddress(ip.getIpAddress()).build());
+            }
+            inputBuilder.setL3(l3Eps);
+        }
+        return inputBuilder.build();
+    }
+
+    private UnregisterEndpointInput createUnregisterEndpointInput(NeutronPort port, ForwardingCtx fwCtx) {
+        UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
+        L2 l2Ep = new L2Builder().setL2Context(fwCtx.getL2BridgeDomain().getId())
+            .setMacAddress(new MacAddress(port.getMacAddress()))
+            .build();
+        inputBuilder.setL2(ImmutableList.of(l2Ep));
+        // TODO Li msunal this has to be rewrite when OFOverlay renderer will support l3-endpoints.
+        // Endpoint probably will not have l3-addresses anymore, because L2 and L3 endpoints should
+        // be registered separately.
+        if (port.getFixedIPs() != null && !port.getFixedIPs().isEmpty()) {
+            inputBuilder.setL3(createL3s(port.getFixedIPs(), fwCtx.getL3Context().getId()));
+        }
+        return inputBuilder.build();
+    }
+
+    private List<L3> createL3s(List<Neutron_IPs> neutronIps, L3ContextId l3ContextId) {
+        List<L3> l3s = new ArrayList<>();
+        for (Neutron_IPs fixedIp : neutronIps) {
+            String ip = fixedIp.getIpAddress();
+            L3 l3 = new L3Builder().setIpAddress(Utils.createIpAddress(ip)).setL3Context(l3ContextId).build();
+            l3s.add(l3);
+        }
+        return l3s;
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronRouterAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronRouterAware.java
new file mode 100644 (file)
index 0000000..e105f8a
--- /dev/null
@@ -0,0 +1,365 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
+import org.opendaylight.neutron.spi.INeutronPortCRUD;
+import org.opendaylight.neutron.spi.INeutronRouterAware;
+import org.opendaylight.neutron.spi.INeutronRouterCRUD;
+import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
+import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronRouter;
+import org.opendaylight.neutron.spi.NeutronRouter_Interface;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.neutron.spi.Neutron_IPs;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+public class NeutronRouterAware implements INeutronRouterAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
+    private final DataBroker dataProvider;
+    private final EndpointService epService;
+
+    public NeutronRouterAware(DataBroker dataProvider, EndpointService epService) {
+        this.dataProvider = checkNotNull(dataProvider);
+        this.epService = checkNotNull(epService);
+    }
+
+    @Override
+    public int canCreateRouter(NeutronRouter router) {
+        LOG.trace("canCreateRouter - {}", router);
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
+            return StatusCode.INTERNAL_SERVER_ERROR;
+        }
+
+        List<NeutronRouter> allRouters = routerInterface.getAllRouters();
+        if (allRouters != null && !allRouters.isEmpty()) {
+            LOG.warn("Illegal state - Neutron mapper does not support multiple routers yet.");
+            return StatusCode.FORBIDDEN;
+        }
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronRouterCreated(NeutronRouter router) {
+        LOG.trace("neutronRouterCreated - {}", router);
+        // TODO Li msunal external gateway
+    }
+
+    @Override
+    public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
+        LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
+        // TODO Li msunal external gateway
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronRouterUpdated(NeutronRouter router) {
+        LOG.trace("neutronRouterUpdated - {}", router);
+        // TODO Li msunal external gateway
+    }
+
+    @Override
+    public int canDeleteRouter(NeutronRouter router) {
+        LOG.trace("canDeleteRouter - {}", router);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronRouterDeleted(NeutronRouter router) {
+        LOG.trace("neutronRouterDeleted - {}", router);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
+        Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
+        if (!potentialEpg.isPresent()) {
+            LOG.warn("Illegal state - Endpoint group {} does not exist.", MappingUtils.EPG_ROUTER_ID.getValue());
+            rwTx.cancel();
+            return;
+        }
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    @Override
+    public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
+        try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
+            L3ContextId l3ContextId = new L3ContextId(router.getID());
+            TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
+            SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
+            Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.subnetIid(tenantId, subnetId), rTx);
+            if (!potentialSubnet.isPresent()) {
+                LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
+                return StatusCode.NOT_FOUND;
+            }
+            Subnet subnet = potentialSubnet.get();
+            L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
+            ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
+            if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextId)) {
+                // TODO Be msunal
+                LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
+                return StatusCode.FORBIDDEN;
+            }
+            return StatusCode.OK;
+        }
+    }
+
+    @Override
+    public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
+            return;
+        }
+
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
+            return;
+        }
+
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
+        L3ContextId l3ContextId = new L3ContextId(router.getID());
+        InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
+        Optional<L3Context> potentialL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                l3ContextIid, rwTx);
+        // add L3 context if missing
+        if (!potentialL3Context.isPresent()) {
+            Name l3ContextName = null;
+            if (router.getName() != null) {
+                l3ContextName = new Name(router.getName());
+            }
+            L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
+                .setName(l3ContextName)
+                .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
+                .build();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context);
+        }
+
+        SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
+        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.subnetIid(tenantId, subnetId), rwTx);
+        if (!potentialSubnet.isPresent()) {
+            LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        // Based on Neutron Northbound - Port representing router interface contains exactly on
+        // fixed IP
+        NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
+        Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(
+                Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress())).build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
+        if (subnet.getParent() == null) {
+            LOG.warn("Illegal state - subnet {} does not have a parent.", subnetId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
+        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
+        if (fwCtx.getL2BridgeDomain() == null) {
+            LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(l3ContextId)
+            .build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
+                l2BridgeDomain);
+
+        // create security rules for router
+        List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
+        if (routerSecRules == null) {
+            rwTx.cancel();
+            return;
+        }
+        for (NeutronSecurityRule routerSecRule : routerSecRules) {
+            boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
+            if (!isRouterSecRuleAdded) {
+                rwTx.cancel();
+                return;
+            }
+        }
+
+        NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
+        List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
+        for (NeutronPort port : portsInNeutronSubnet) {
+            boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
+            if (!isPortAdded) {
+                rwTx.cancel();
+                return;
+            }
+        }
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
+            ReadTransaction rTx) {
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
+        Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
+        if (firstIp == null) {
+            LOG.warn("Illegal state - Router port does not have an IP address.");
+            return null;
+        }
+        SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
+        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
+        if (!potentialSubnet.isPresent()) {
+            LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
+            return null;
+        }
+        IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
+        NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
+                true);
+        NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
+                false);
+        return ImmutableList.of(routerRuleEgress, routerRuleIngress);
+    }
+
+    private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
+        if (fixedIPs == null || fixedIPs.isEmpty()) {
+            return null;
+        }
+        Neutron_IPs neutron_Ip = fixedIPs.get(0);
+        if (fixedIPs.size() > 1) {
+            LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
+                    neutron_Ip);
+        }
+        return neutron_Ip;
+    }
+
+    private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
+            EndpointGroupId consumerEpgId, boolean isEgress) {
+        NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
+        dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
+        dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
+        dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
+        if (isEgress) {
+            dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
+            dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
+        } else {
+            dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
+            dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
+        }
+        if (ipSubnet.getIpv4Prefix() != null) {
+            dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
+        } else {
+            dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
+        }
+        return dhcpSecRule;
+    }
+
+    @Override
+    public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
+        LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
+            return;
+        }
+
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
+        L3ContextId l3ContextId = new L3ContextId(router.getID());
+        SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
+        InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
+        DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
+
+        Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.subnetIid(tenantId, subnetId), rwTx);
+        if (!potentialSubnet.isPresent()) {
+            LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
+
+        L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
+        ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
+        if (fwCtx.getL2BridgeDomain() == null) {
+            LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
+                IidFactory.networkMappingIid(l2FdId), rwTx);
+        if (!potentialNetworkMapping.isPresent()) {
+            LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
+                potentialNetworkMapping.get().getL3ContextId()).build();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
+                l2BridgeDomain);
+
+        NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
+        List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
+        for (NeutronPort port : portsInNeutronSubnet) {
+            boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
+            if (!isPortAdded) {
+                rwTx.cancel();
+                return;
+            }
+        }
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityGroupAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityGroupAware.java
new file mode 100644 (file)
index 0000000..686d119
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2015 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.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.neutron.spi.INeutronSecurityGroupAware;
+import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ListMultimap;
+
+public class NeutronSecurityGroupAware implements INeutronSecurityGroupAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityGroupAware.class);
+    private final DataBroker dataProvider;
+
+    public NeutronSecurityGroupAware(DataBroker dataProvider) {
+        this.dataProvider = checkNotNull(dataProvider);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canCreateNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup) {
+        LOG.trace("canCreateNeutronSecurityGroup - {}", securityGroup);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupCreated(org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public void neutronSecurityGroupCreated(NeutronSecurityGroup secGroup) {
+        LOG.trace("neutronSecurityGroupCreated - {}", secGroup);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        boolean isSecGroupCreated = addNeutronSecurityGroup(secGroup, rwTx);
+        if (isSecGroupCreated) {
+            DataStoreHelper.submitToDs(rwTx);
+        } else {
+            rwTx.cancel();
+        }
+    }
+
+    public static boolean addNeutronSecurityGroup(NeutronSecurityGroup secGroup, ReadWriteTransaction rwTx) {
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(secGroup.getSecurityGroupTenantID()));
+        EndpointGroupId providerEpgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
+        EndpointGroupBuilder providerEpgBuilder = new EndpointGroupBuilder().setId(providerEpgId);
+        providerEpgBuilder.setName(new Name(MappingUtils.NEUTRON_GROUP__ + Strings.nullToEmpty(secGroup.getSecurityGroupName())));
+        providerEpgBuilder.setDescription(new Description(MappingUtils.NEUTRON_GROUP__
+                + Strings.nullToEmpty(secGroup.getSecurityGroupDescription())));
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId),
+                providerEpgBuilder.build(), true);
+        List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
+        SortedSecurityGroupRules sortedSecGrpRules = new SortedSecurityGroupRules(secRules);
+        ListMultimap<EndpointGroupId, NeutronSecurityRule> secRuleByRemoteSecGrpId = sortedSecGrpRules.secRuleByRemoteSecGrpId;
+        for (EndpointGroupId consumerEpgId : secRuleByRemoteSecGrpId.keySet()) {
+            addEpgIfMissing(tenantId, consumerEpgId, rwTx);
+            boolean areSecRulesAdded = addNeutronSecurityRule(secRuleByRemoteSecGrpId.get(consumerEpgId), rwTx);
+            if (!areSecRulesAdded) {
+                return false;
+            }
+        }
+        ListMultimap<IpPrefix, NeutronSecurityRule> secRuleByRemoteIpPrefix = sortedSecGrpRules.secRuleByRemoteIpPrefix;
+        for (IpPrefix remoteIpPrefex : secRuleByRemoteIpPrefix.keySet()) {
+            boolean areSecRulesAdded = addNeutronSecurityRule(secRuleByRemoteIpPrefix.get(remoteIpPrefex), rwTx);
+            if (!areSecRulesAdded) {
+                return false;
+            }
+        }
+        boolean areSecRulesAdded = addNeutronSecurityRule(sortedSecGrpRules.secRulesWithoutRemote, rwTx);
+        if (!areSecRulesAdded) {
+            return false;
+        }
+        return true;
+    }
+
+    public static void addEpgIfMissing(TenantId tenantId, EndpointGroupId epgId, ReadWriteTransaction rwTx) {
+        InstanceIdentifier<EndpointGroup> epgIid = IidFactory.endpointGroupIid(tenantId, epgId);
+        Optional<EndpointGroup> potentialConsumerEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                epgIid, rwTx);
+        if (!potentialConsumerEpg.isPresent()) {
+            EndpointGroup epg = new EndpointGroupBuilder().setId(epgId)
+                .setName(new Name(MappingUtils.NEUTRON_GROUP__))
+                .setDescription(new Description(MappingUtils.NEUTRON_GROUP__ + "EPG was created just based on remote group ID from a security rule."))
+                .build();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, epgIid, epg);
+        }
+    }
+
+    private static boolean addNeutronSecurityRule(List<NeutronSecurityRule> secRules, ReadWriteTransaction rwTx) {
+        for (NeutronSecurityRule secRule : secRules) {
+            boolean isSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(secRule, rwTx);
+            if (!isSecRuleAdded) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canUpdateNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup,
+     *      org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original) {
+        LOG.warn("canUpdateNeutronSecurityGroup - Never should be called "
+                + "- neutron API does not allow UPDATE on neutron security group. \nDelta: {} \nOriginal: {}", delta,
+                original);
+        return StatusCode.BAD_REQUEST;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupUpdated(org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup) {
+        LOG.warn("neutronSecurityGroupUpdated - Never should be called "
+                + "- neutron API does not allow UPDATE on neutron security group. \nSecurity group: {}", securityGroup);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canDeleteNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup) {
+        LOG.trace("canDeleteNeutronSecurityGroup - {}", securityGroup);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupDeleted(org.opendaylight.neutron.spi.NeutronSecurityGroup)
+     */
+    @Override
+    public void neutronSecurityGroupDeleted(NeutronSecurityGroup secGroup) {
+        LOG.trace("neutronSecurityGroupDeleted - {}", secGroup);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
+        if (secRules != null) {
+            boolean areSecRulesAdded = deleteNeutronSecurityRules(secRules, rwTx);
+            if (!areSecRulesAdded) {
+                rwTx.cancel();
+                return;
+            }
+        }
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(secGroup.getSecurityGroupTenantID()));
+        EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
+        Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
+        if (!potentialEpg.isPresent()) {
+            LOG.warn("Illegal state - Endpoint group {} does not exist.", epgId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    private boolean deleteNeutronSecurityRules(List<NeutronSecurityRule> secRules, ReadWriteTransaction rwTx) {
+        for (NeutronSecurityRule secRule : secRules) {
+            boolean isSecRuleDeleted = NeutronSecurityRuleAware.deleteNeutronSecurityRule(secRule, rwTx);
+            if (!isSecRuleDeleted) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static final class SortedSecurityGroupRules {
+
+        private final ListMultimap<EndpointGroupId, NeutronSecurityRule> secRuleByRemoteSecGrpId;
+        private final ListMultimap<IpPrefix, NeutronSecurityRule> secRuleByRemoteIpPrefix;
+        private final List<NeutronSecurityRule> secRulesWithoutRemote;
+
+        private SortedSecurityGroupRules(List<NeutronSecurityRule> securityRules) {
+            Preconditions.checkNotNull(securityRules);
+            ListMultimap<EndpointGroupId, NeutronSecurityRule> tmpSecRuleByRemoteSecGrpId = ArrayListMultimap.create();
+            ListMultimap<IpPrefix, NeutronSecurityRule> tmpSecRuleByRemoteIpPrefix = ArrayListMultimap.create();
+            List<NeutronSecurityRule> tmpSecRulesWithoutRemote = new ArrayList<>();
+            for (NeutronSecurityRule securityRule : securityRules) {
+                String remoteSecGroupId = securityRule.getSecurityRemoteGroupID();
+                String remoteIpPrefix = securityRule.getSecurityRuleRemoteIpPrefix();
+                boolean isRemoteSecGroupId = remoteSecGroupId != null && !"null".equals(remoteSecGroupId);
+                boolean isRemoteIpPrefix = remoteIpPrefix != null && !"null".equals(remoteIpPrefix);
+                if (isRemoteSecGroupId && isRemoteIpPrefix) {
+                    throw new IllegalArgumentException("Either remote group id or ip prefix "
+                            + "must be speciefied in neutron security group rule." + securityRule.toString());
+                }
+                if (isRemoteSecGroupId) {
+                    tmpSecRuleByRemoteSecGrpId.put(new EndpointGroupId(remoteSecGroupId), securityRule);
+                } else if (isRemoteIpPrefix) {
+                    tmpSecRuleByRemoteIpPrefix.put(Utils.createIpPrefix(remoteIpPrefix), securityRule);
+                } else {
+                    tmpSecRulesWithoutRemote.add(securityRule);
+                }
+            }
+            secRuleByRemoteSecGrpId = ImmutableListMultimap.copyOf(tmpSecRuleByRemoteSecGrpId);
+            secRuleByRemoteIpPrefix = ImmutableListMultimap.copyOf(tmpSecRuleByRemoteIpPrefix);
+            secRulesWithoutRemote = ImmutableList.copyOf(tmpSecRulesWithoutRemote);
+        }
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityRuleAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSecurityRuleAware.java
new file mode 100644 (file)
index 0000000..bb60a5d
--- /dev/null
@@ -0,0 +1,373 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.UUID;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ContractBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+
+public class NeutronSecurityRuleAware implements INeutronSecurityRuleAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleAware.class);
+    private final DataBroker dataProvider;
+
+    public NeutronSecurityRuleAware(DataBroker dataProvider) {
+        this.dataProvider = checkNotNull(dataProvider);
+    }
+
+    @Override
+    public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule) {
+        LOG.trace("canCreateNeutronSecurityRule - {}", securityRule);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronSecurityRuleCreated(NeutronSecurityRule securityRule) {
+        LOG.trace("neutronSecurityRuleCreated - {}", securityRule);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(securityRule, rwTx);
+        if (isNeutronSecurityRuleAdded) {
+            DataStoreHelper.submitToDs(rwTx);
+        } else {
+            rwTx.cancel();
+        }
+    }
+
+    /**
+     * <b>ASSUMPTION</b>: Endpoint group with id
+     * {@link NeutronSecurityRule#getSecurityRuleGroupID()} and
+     * endpoint group with id {@link NeutronSecurityRule#getSecurityRemoteGroupID()} already exist
+     * in transaction.
+     *
+     * @param secRule neutron security rule from which GBP entities are created
+     * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
+     *        the transaction.
+     * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
+     *         the transaction may contain just partial result
+     */
+    public static boolean addNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
+        TransformSecRule transform = new TransformSecRule(secRule);
+        TenantId tenantId = transform.getTenantId();
+        EndpointGroupId providerEpgId = transform.getProviderEpgId();
+        EndpointGroupId consumerEpgId = transform.getConsumerEpgId();
+        SubjectName subjectName = transform.getSubjectName();
+
+        Optional<ContractId> potentialContractId = readContractIdFromEpgPairToContractMapping(providerEpgId,
+                consumerEpgId, rwTx);
+        ContractId contractId = null;
+        if (potentialContractId.isPresent()) {
+            contractId = potentialContractId.get();
+            Optional<Subject> potentialSubject = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.subjectIid(tenantId, contractId, subjectName), rwTx);
+            if (!potentialSubject.isPresent()) {
+                // it also means that clause for this subject does not exist
+                rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subjectIid(tenantId, contractId, subjectName),
+                        transform.createSubject());
+                rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                        IidFactory.clauseIid(tenantId, contractId, transform.getClauseName()), transform.createClause());
+            }
+        } else {
+            // check assumption that provider EPG exists
+            Optional<EndpointGroup> potentialProviderEpg = DataStoreHelper.readFromDs(
+                    LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId), rwTx);
+            if (!potentialProviderEpg.isPresent()) {
+                LOG.warn("Illegal state - Endpoint group {} does not exist.", providerEpgId.getValue());
+                return false;
+            }
+
+            if (providerEpgId.equals(consumerEpgId)) {
+                EndpointGroup providerConsumerEpg = potentialProviderEpg.get();
+                if (providerConsumerEpg.getIntraGroupPolicy() == null
+                        || !providerConsumerEpg.getIntraGroupPolicy().equals(IntraGroupPolicy.RequireContract)) {
+                    EndpointGroup newProviderConsumerEpg = new EndpointGroupBuilder(providerConsumerEpg).setIntraGroupPolicy(
+                            IntraGroupPolicy.RequireContract)
+                        .build();
+                    rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId),
+                            newProviderConsumerEpg);
+                }
+            } else {
+                Optional<EndpointGroup> potentialConsumerEpg = DataStoreHelper.readFromDs(
+                        LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, consumerEpgId), rwTx);
+                if (!potentialConsumerEpg.isPresent()) {
+                    if (MappingUtils.EPG_ANY_ID.equals(consumerEpgId)) {
+                        EndpointGroup epgAny = createEpgAny();
+                        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ANY_ID),
+                                epgAny);
+                    } else {
+                        LOG.warn("Illegal state - Endpoint group {} does not exist.", consumerEpgId.getValue());
+                        return false;
+                    }
+                }
+            }
+            // creates and stores contract with clause and subject
+            Subject subject = transform.createSubject();
+            Clause clause = transform.createClause();
+            Contract contract = createContract(clause, subject);
+            contractId = contract.getId();
+            rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId), contract);
+            putEpgPairToContractMapping(providerEpgId, consumerEpgId, contractId, rwTx);
+
+            // adds provider and consumer named selectors
+            ProviderNamedSelector providerSelector = createProviderNamedSelector(contractId);
+            rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.providerNamedSelectorIid(tenantId, providerEpgId, providerSelector.getName()),
+                    providerSelector);
+            ConsumerNamedSelector consumerSelector = createConsumerNamedSelector(contractId);
+            rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.consumerNamedSelectorIid(tenantId, consumerEpgId, consumerSelector.getName()),
+                    consumerSelector);
+        }
+
+        // create classifier-instance
+        ClassifierName classifierName = transform.getClassifierName();
+        ClassifierInstance classifier = transform.createClassifier();
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.classifierInstanceIid(tenantId, classifierName),
+                classifier, true);
+        // create action-instance if it does not exist yet
+        Optional<ActionInstance> potentialAction = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.actionInstanceIid(tenantId, MappingUtils.ACTION_ALLOW.getName()), rwTx);
+        if (!potentialAction.isPresent()) {
+            rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                    IidFactory.actionInstanceIid(tenantId, MappingUtils.ACTION_ALLOW.getName()),
+                    MappingUtils.ACTION_ALLOW, true);
+        }
+
+        // create rule
+        Rule rule = transform.createRule(0);
+        rwTx.put(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.ruleIid(tenantId, contractId, subjectName, rule.getName()), rule);
+        return true;
+    }
+
+    private static EndpointGroup createEpgAny() {
+        return new EndpointGroupBuilder().setId(MappingUtils.EPG_ANY_ID)
+                .setDescription(new Description(MappingUtils.NEUTRON_RULE__ + "epg_any"))
+                .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
+                .build();
+    }
+
+    @Override
+    public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original) {
+        LOG.warn("canUpdateNeutronSecurityRule - Never should be called "
+                + "- neutron API does not allow UPDATE on neutron security group rule. \nDelta: {} \nOriginal: {}",
+                delta, original);
+        return StatusCode.BAD_REQUEST;
+    }
+
+    @Override
+    public void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule) {
+        LOG.warn("neutronSecurityRuleUpdated - Never should be called "
+                + "- neutron API does not allow UPDATE on neutron security group rule. \nSecurity group rule: {}",
+                securityRule);
+    }
+
+    @Override
+    public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule) {
+        LOG.trace("canDeleteNeutronSecurityRule - {}", securityRule);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    @Override
+    public void neutronSecurityRuleDeleted(NeutronSecurityRule secRule) {
+        LOG.trace("neutronSecurityRuleCreated - {}", secRule);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        boolean isNeutronSecurityRuleDelete = deleteNeutronSecurityRule(secRule, rwTx);
+        if (isNeutronSecurityRuleDelete) {
+            DataStoreHelper.submitToDs(rwTx);
+        } else {
+            DataStoreHelper.submitToDs(rwTx);
+        }
+    }
+
+    /**
+     * @param secRule neutron security rule from which GBP entities are deleted
+     * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
+     *        the transaction.
+     * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
+     *         the transaction may contain just partial result
+     */
+    public static boolean deleteNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
+        TransformSecRule transform = new TransformSecRule(secRule);
+        TenantId tenantId = transform.getTenantId();
+        EndpointGroupId providerEpgId = transform.getProviderEpgId();
+        EndpointGroupId consumerEpgId = transform.getConsumerEpgId();
+
+        Optional<ContractId> potentialContractId = readContractIdFromEpgPairToContractMapping(providerEpgId,
+                consumerEpgId, rwTx);
+        if (!potentialContractId.isPresent()) {
+            LOG.warn("Illegal state - mapping EPG pair (provider EPG {} consumer EPG {}) does not exist.",
+                    providerEpgId.getValue(), consumerEpgId.getValue());
+            return false;
+        }
+
+        ContractId contractId = potentialContractId.get();
+        ClassifierName classifierName = transform.getClassifierName();
+        InstanceIdentifier<ClassifierInstance> classifierIid = IidFactory.classifierInstanceIid(tenantId,
+                classifierName);
+        Optional<ClassifierInstance> potentialClassifier = DataStoreHelper.removeIfExists(
+                LogicalDatastoreType.CONFIGURATION, classifierIid, rwTx);
+        if (!potentialClassifier.isPresent()) {
+            LOG.warn("Illegal state - classifier-instance {} does not exist. {}", classifierName.getValue(),
+                    classifierIid);
+            return false;
+        }
+
+        RuleName ruleName = transform.getRuleName();
+        SubjectName subjectName = transform.getSubjectName();
+        InstanceIdentifier<Rule> ruleIid = IidFactory.ruleIid(tenantId, contractId, subjectName, ruleName);
+        Optional<Rule> potentionalRule = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, ruleIid,
+                rwTx);
+        if (!potentionalRule.isPresent()) {
+            LOG.warn("Illegal state - rule {} does not exist. {}", ruleName.getValue(), ruleIid);
+            return false;
+        }
+
+        InstanceIdentifier<Subject> subjectIid = IidFactory.subjectIid(tenantId, contractId, subjectName);
+        Optional<Subject> potentionalSubject = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                subjectIid, rwTx);
+        if (!potentionalSubject.isPresent()) {
+            LOG.warn("Illegal state - subject {} does not exist. {}", subjectName.getValue(), subjectName);
+            return false;
+        }
+
+        ClauseName clauseName = transform.getClauseName();
+        InstanceIdentifier<Clause> clauseIid = IidFactory.clauseIid(tenantId, contractId, clauseName);
+        Optional<Clause> potentialClause = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, clauseIid,
+                rwTx);
+        if (!potentialClause.isPresent()) {
+            LOG.warn("Illegal state - clause {} does not exist. {}", clauseName.getValue(), clauseIid);
+            return false;
+        }
+
+        Subject subject = potentionalSubject.get();
+        if (subject.getRule() == null || subject.getRule().isEmpty()) {
+            rwTx.delete(LogicalDatastoreType.CONFIGURATION, clauseIid);
+            rwTx.delete(LogicalDatastoreType.CONFIGURATION, subjectIid);
+        }
+
+        InstanceIdentifier<Contract> contractIid = IidFactory.contractIid(tenantId, contractId);
+        Optional<Contract> potentialContract = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                contractIid, rwTx);
+        if (!potentialContract.isPresent()) {
+            LOG.warn("Illegal state - contract {} does not exist. {}", contractId.getValue(), contractIid);
+            return false;
+        }
+
+        Contract contract = potentialContract.get();
+        if (contract.getSubject() == null || contract.getSubject().isEmpty()) {
+            // remove contract and named selectors from EPGs
+            rwTx.delete(LogicalDatastoreType.CONFIGURATION, contractIid);
+            SelectorName providerSelectorName = createNameOfNamedSelector(contractId);
+            InstanceIdentifier<ProviderNamedSelector> providerSelectorIid = IidFactory.providerNamedSelectorIid(
+                    tenantId, providerEpgId, providerSelectorName);
+            Optional<ProviderNamedSelector> potentialProviderSelector = DataStoreHelper.removeIfExists(
+                    LogicalDatastoreType.CONFIGURATION, providerSelectorIid, rwTx);
+            if (!potentialProviderSelector.isPresent()) {
+                LOG.warn("Illegal state - provider-name-selector {} does not exist. {}",
+                        providerSelectorName.getValue(), providerSelectorIid);
+                return false;
+            }
+            SelectorName consumerSelectorName = createNameOfNamedSelector(contractId);
+            InstanceIdentifier<ConsumerNamedSelector> consumerSelectorIid = IidFactory.consumerNamedSelectorIid(
+                    tenantId, consumerEpgId, consumerSelectorName);
+            Optional<ConsumerNamedSelector> potentialConsuemrSelector = DataStoreHelper.removeIfExists(
+                    LogicalDatastoreType.CONFIGURATION, consumerSelectorIid, rwTx);
+            if (!potentialConsuemrSelector.isPresent()) {
+                LOG.warn("Illegal state - consumer-name-selector {} does not exist. {}",
+                        consumerSelectorName.getValue(), consumerSelectorIid);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static Optional<ContractId> readContractIdFromEpgPairToContractMapping(EndpointGroupId providerEpgId,
+            EndpointGroupId consumerEpgId, ReadTransaction rTx) {
+        Optional<EndpointGroupPairToContractMapping> potentialMapping = DataStoreHelper.readFromDs(
+                LogicalDatastoreType.OPERATIONAL,
+                IidFactory.endpointGroupPairToContractMappingIid(providerEpgId, consumerEpgId), rTx);
+        if (potentialMapping.isPresent()) {
+            return Optional.of(potentialMapping.get().getContractId());
+        }
+        return Optional.absent();
+    }
+
+    private static void putEpgPairToContractMapping(EndpointGroupId providerEpgId, EndpointGroupId consumerEpgId,
+            ContractId contractId, WriteTransaction wTx) {
+        EndpointGroupPairToContractMapping epgPairToContractMapping = new EndpointGroupPairToContractMappingBuilder().setProviderEpgId(
+                providerEpgId)
+            .setConsumerEpgId(consumerEpgId)
+            .setContractId(contractId)
+            .build();
+        wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointGroupPairToContractMappingIid(
+                epgPairToContractMapping.getProviderEpgId(), epgPairToContractMapping.getConsumerEpgId()),
+                epgPairToContractMapping, true);
+    }
+
+    private static Contract createContract(Clause clause, Subject subject) {
+        ContractId contractId = new ContractId(UUID.randomUUID().toString());
+        return new ContractBuilder().setId(contractId)
+            .setClause(ImmutableList.of(clause))
+            .setSubject(ImmutableList.of(subject))
+            .build();
+    }
+
+    private static ProviderNamedSelector createProviderNamedSelector(ContractId contractId) {
+        return new ProviderNamedSelectorBuilder().setName(createNameOfNamedSelector(contractId))
+            .setContract(ImmutableList.of(contractId))
+            .build();
+    }
+
+    private static ConsumerNamedSelector createConsumerNamedSelector(ContractId contractId) {
+        return new ConsumerNamedSelectorBuilder().setName(createNameOfNamedSelector(contractId))
+            .setContract(ImmutableList.of(contractId))
+            .build();
+    }
+
+    private static SelectorName createNameOfNamedSelector(ContractId contractId) {
+        return new SelectorName(MappingUtils.NEUTRON_RULE__ + contractId.getValue());
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSubnetAware.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/NeutronSubnetAware.java
new file mode 100644 (file)
index 0000000..f1df5d1
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015 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.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.neutron.spi.INeutronSubnetAware;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class NeutronSubnetAware implements INeutronSubnetAware {
+
+    private final static Logger LOG = LoggerFactory.getLogger(NeutronSubnetAware.class);
+    private final DataBroker dataProvider;
+
+    public NeutronSubnetAware(DataBroker dataProvider) {
+        this.dataProvider = checkNotNull(dataProvider);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#canCreateSubnet(org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public int canCreateSubnet(NeutronSubnet subnet) {
+        LOG.trace("canCreateSubnet - {}", subnet);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#neutronSubnetCreated(org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public void neutronSubnetCreated(NeutronSubnet neutronSubnet) {
+        LOG.trace("neutronSubnetCreated - {}", neutronSubnet);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        SubnetId subnetId = new SubnetId(Utils.normalizeUuid(neutronSubnet.getID()));
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(neutronSubnet.getTenantID()));
+        Subnet subnet = createSubnet(neutronSubnet);
+        rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet, true);
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+    private Subnet createSubnet(NeutronSubnet neutronSubnet) {
+        SubnetBuilder subnetBuilder = new SubnetBuilder();
+        subnetBuilder.setId(new SubnetId(neutronSubnet.getID()));
+        subnetBuilder.setParent(new ContextId(neutronSubnet.getNetworkUUID()));
+        if (neutronSubnet.getName() != null) {
+            subnetBuilder.setName(new Name(neutronSubnet.getName()));
+        }
+        subnetBuilder.setIpPrefix(Utils.createIpPrefix(neutronSubnet.getCidr()));
+        return subnetBuilder.build();
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#canUpdateSubnet(org.opendaylight.neutron.spi.NeutronSubnet,
+     *      org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public int canUpdateSubnet(NeutronSubnet delta, NeutronSubnet original) {
+        LOG.trace("canUpdateSubnet - delta: {} original: {}", delta, original);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#neutronSubnetUpdated(org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public void neutronSubnetUpdated(NeutronSubnet subnet) {
+        LOG.trace("neutronSubnetUpdated - {}", subnet);
+        neutronSubnetCreated(subnet);
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#canDeleteSubnet(org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public int canDeleteSubnet(NeutronSubnet subnet) {
+        LOG.trace("canDeleteSubnet - {}", subnet);
+        // nothing to consider
+        return StatusCode.OK;
+    }
+
+    /**
+     * @see org.opendaylight.neutron.spi.INeutronSubnetAware#neutronSubnetDeleted(org.opendaylight.neutron.spi.NeutronSubnet)
+     */
+    @Override
+    public void neutronSubnetDeleted(NeutronSubnet neutronSubnet) {
+        LOG.trace("neutronSubnetDeleted - {}", neutronSubnet);
+        ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
+        SubnetId subnetId = new SubnetId(Utils.normalizeUuid(neutronSubnet.getID()));
+        TenantId tenantId = new TenantId(Utils.normalizeUuid(neutronSubnet.getTenantID()));
+        Optional<Subnet> potentialSubnet = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.subnetIid(tenantId, subnetId), rwTx);
+        if (!potentialSubnet.isPresent()) {
+            LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
+            rwTx.cancel();
+            return;
+        }
+
+        DataStoreHelper.submitToDs(rwTx);
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/StatusCode.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/StatusCode.java
new file mode 100644 (file)
index 0000000..e0dfb15
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
+
+/**
+ * HTTP status codes
+ */
+public final class StatusCode {
+
+    public static final int OK = 200;
+    public static final int BAD_REQUEST = 400;
+    public static final int FORBIDDEN = 403;
+    public static final int NOT_FOUND = 404;
+    public static final int INTERNAL_SERVER_ERROR = 500;
+
+    private StatusCode() {
+        throw new UnsupportedOperationException("Cannot create an instance.");
+    }
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/TransformSecRule.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/mapping/TransformSecRule.java
new file mode 100644 (file)
index 0000000..8940bb9
--- /dev/null
@@ -0,0 +1,263 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
+import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.EtherTypeClassifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.IpProtoClassifier;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;
+import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef.ConnectionTracking;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.ClauseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.SubjectBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ConsumerMatchersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.ProviderMatchersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.EndpointIdentificationConstraintsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.endpoint.identification.constraints.L3EndpointIdentificationConstraintsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.consumer.matchers.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraintBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstanceBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+public class TransformSecRule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TransformSecRule.class);
+    private static final List<ActionRef> ACTION_REF_ALLOW = ImmutableList.of(new ActionRefBuilder().setName(
+            MappingUtils.ACTION_ALLOW.getName())
+        .setOrder(0)
+        .build());
+    private final NeutronSecurityRule secRule;
+    private final TenantId tenantId;
+    private final EndpointGroupId providerEpgId;
+    private final EndpointGroupId consumerEpgId;
+    private final SubjectName subjectName;
+    private final ClauseName clauseName;
+    private final IpPrefix ipPrefix;
+    private final int subjectOrder;
+    private final ClassifierName classifierName;
+    private final RuleName ruleName;
+
+    /**
+     * If a {@link NeutronSecurityRule#getSecurityRuleGroupID()} is {@link MappingUtils#EPG_DHCP_ID}
+     * or {@link MappingUtils#EPG_ROUTER_ID} then the neutron security rule can contain remote ip
+     * prefix besides remote ip security group. I this case {@link #getConsumerEpgId()} returns remote security group id.
+     *
+     * @param secRule
+     */
+    public TransformSecRule(NeutronSecurityRule secRule) {
+        this.secRule = checkNotNull(secRule);
+        tenantId = new TenantId(Utils.normalizeUuid(secRule.getSecurityRuleTenantID()));
+        providerEpgId = new EndpointGroupId(secRule.getSecurityRuleGroupID());
+        if (!Strings.isNullOrEmpty(secRule.getSecurityRemoteGroupID())) {
+            consumerEpgId = new EndpointGroupId(secRule.getSecurityRemoteGroupID());
+            if (isEpgIdRouterOrDhcp(providerEpgId) && !Strings.isNullOrEmpty(secRule.getSecurityRuleRemoteIpPrefix())) {
+                ipPrefix = Utils.createIpPrefix(secRule.getSecurityRuleRemoteIpPrefix());
+            } else {
+                ipPrefix = null;
+            }
+            subjectOrder = 0;
+        } else if (!Strings.isNullOrEmpty(secRule.getSecurityRuleRemoteIpPrefix())) {
+            consumerEpgId = MappingUtils.EPG_ANY_ID;
+            ipPrefix = Utils.createIpPrefix(secRule.getSecurityRuleRemoteIpPrefix());
+            subjectOrder = 0;
+        } else {
+            consumerEpgId = MappingUtils.EPG_ANY_ID;
+            ipPrefix = null;
+            subjectOrder = 1;
+        }
+        subjectName = createSubjectName();
+        clauseName = new ClauseName(subjectName.getValue());
+        classifierName = new ClassifierName(MappingUtils.NEUTRON_RULE__ + secRule.getSecurityRuleUUID());
+        ruleName = new RuleName(MappingUtils.NEUTRON_RULE__ + "Allow--" + classifierName.getValue());
+    }
+
+    private SubjectName createSubjectName() {
+        if (ipPrefix == null) {
+            return new SubjectName(MappingUtils.NEUTRON_RULE__ + providerEpgId.getValue() + "__"
+                    + consumerEpgId.getValue());
+        }
+        String prefix = Utils.getStringIpPrefix(ipPrefix).replace('/', '_');
+        return new SubjectName(MappingUtils.NEUTRON_RULE__ + providerEpgId.getValue() + "__" + prefix + "__"
+                + consumerEpgId.getValue());
+    }
+
+    public Clause createClause() {
+        ClauseBuilder clauseBuilder = new ClauseBuilder().setName(clauseName).setSubjectRefs(
+                ImmutableList.of(subjectName));
+        if (ipPrefix != null) {
+            clauseBuilder.setConsumerMatchers(new ConsumerMatchersBuilder().setEndpointIdentificationConstraints(
+                    new EndpointIdentificationConstraintsBuilder().setL3EndpointIdentificationConstraints(
+                            new L3EndpointIdentificationConstraintsBuilder().setPrefixConstraint(
+                                    ImmutableList.<PrefixConstraint>of(new PrefixConstraintBuilder().setIpPrefix(
+                                            ipPrefix).build())).build()).build()).build());
+            if (isEpgIdRouterOrDhcp(providerEpgId)) {
+                clauseBuilder.setProviderMatchers(new ProviderMatchersBuilder().setEndpointIdentificationConstraints(
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.EndpointIdentificationConstraintsBuilder().setL3EndpointIdentificationConstraints(
+                                new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.endpoint.identification.constraints.L3EndpointIdentificationConstraintsBuilder().setPrefixConstraint(
+                                        ImmutableList.<org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraint>of(new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.clause.provider.matchers.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraintBuilder().setIpPrefix(
+                                                ipPrefix)
+                                            .build()))
+                                    .build())
+                            .build())
+                    .build());
+            }
+        }
+        return clauseBuilder.build();
+    }
+
+    private static boolean isEpgIdRouterOrDhcp(EndpointGroupId epgId) {
+        return (MappingUtils.EPG_ROUTER_ID.equals(epgId) || MappingUtils.EPG_DHCP_ID.equals(epgId));
+    }
+
+    public ClassifierInstance createClassifier() {
+        ClassifierInstanceBuilder classifierBuilder = new ClassifierInstanceBuilder().setName(classifierName);
+        List<ParameterValue> params = new ArrayList<>();
+        Integer portMin = secRule.getSecurityRulePortMin();
+        Integer portMax = secRule.getSecurityRulePortMax();
+        if (portMin != null && portMax != null) {
+            classifierBuilder.setClassifierDefinitionId(L4Classifier.DEFINITION.getId());
+            if (portMin.equals(portMax)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(L4Classifier.DST_PORT_PARAM))
+                    .setIntValue(portMin.longValue())
+                    .build());
+            } else {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(L4Classifier.DST_PORT_RANGE_PARAM))
+                    .setRangeValue(
+                            new RangeValueBuilder().setMin(portMin.longValue()).setMax(portMax.longValue()).build())
+                    .build());
+            }
+        }
+        String protocol = secRule.getSecurityRuleProtocol();
+        if (!Strings.isNullOrEmpty(protocol)) {
+            if (classifierBuilder.getClassifierDefinitionId() == null) {
+                classifierBuilder.setClassifierDefinitionId(IpProtoClassifier.DEFINITION.getId());
+            }
+            if (NeutronUtils.TCP.equals(protocol)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(IpProtoClassifier.PROTO_PARAM))
+                    .setIntValue(IpProtoClassifier.TCP_VALUE)
+                    .build());
+            } else if (NeutronUtils.UDP.equals(protocol)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(IpProtoClassifier.PROTO_PARAM))
+                    .setIntValue(IpProtoClassifier.UDP_VALUE)
+                    .build());
+            } else if (NeutronUtils.ICMP.equals(protocol)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(IpProtoClassifier.PROTO_PARAM))
+                    .setIntValue(1L)
+                    .build());
+            } else if (NeutronUtils.NULL.equals(protocol)) {
+                LOG.debug("Protocol is not specified in security group rule {}", secRule.getSecurityRuleUUID());
+            } else {
+                throw new IllegalArgumentException("Protocol " + protocol + " is not supported.");
+            }
+        }
+        String ethertype = secRule.getSecurityRuleEthertype();
+        if (!Strings.isNullOrEmpty(ethertype)) {
+            if (classifierBuilder.getClassifierDefinitionId() == null) {
+                classifierBuilder.setClassifierDefinitionId(EtherTypeClassifier.DEFINITION.getId());
+            }
+            if (NeutronUtils.IPv4.equals(ethertype)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(EtherTypeClassifier.ETHERTYPE_PARAM))
+                    .setIntValue(EtherTypeClassifier.IPv4_VALUE)
+                    .build());
+            } else if (NeutronUtils.IPv6.equals(ethertype)) {
+                params.add(new ParameterValueBuilder().setName(new ParameterName(EtherTypeClassifier.ETHERTYPE_PARAM))
+                    .setIntValue(EtherTypeClassifier.IPv6_VALUE)
+                    .build());
+            } else {
+                throw new IllegalArgumentException("Ethertype " + ethertype + " is not supported.");
+            }
+        }
+        return classifierBuilder.setParameterValue(params).build();
+    }
+
+    public Rule createRule(int order) {
+        return new RuleBuilder().setName(ruleName)
+            .setOrder(order)
+            .setActionRef(ACTION_REF_ALLOW)
+            .setClassifierRef(ImmutableList.of(createClassifierRef()))
+            .build();
+    }
+
+    public Subject createSubject() {
+        return new SubjectBuilder().setName(subjectName).setOrder(subjectOrder).build();
+    }
+
+    private ClassifierRef createClassifierRef() {
+        ClassifierRefBuilder classifierRefBuilder = new ClassifierRefBuilder().setName(classifierName)
+            .setConnectionTracking(ConnectionTracking.Reflexive)
+            .setInstanceName(classifierName);
+        String direction = secRule.getSecurityRuleDirection();
+        if (NeutronUtils.INGRESS.equals(direction)) {
+            classifierRefBuilder.setDirection(Direction.In);
+        } else if (NeutronUtils.EGRESS.equals(direction)) {
+            classifierRefBuilder.setDirection(Direction.Out);
+        } else {
+            throw new IllegalArgumentException("Direction " + direction + " from security group rule "
+                    + secRule.getSecurityRuleUUID() + " is not supported. Direction can be only 'ingress' or 'egress'.");
+        }
+        return classifierRefBuilder.build();
+    }
+
+    public TenantId getTenantId() {
+        return tenantId;
+    }
+
+    public EndpointGroupId getProviderEpgId() {
+        return providerEpgId;
+    }
+
+    public EndpointGroupId getConsumerEpgId() {
+        return consumerEpgId;
+    }
+
+    public SubjectName getSubjectName() {
+        return subjectName;
+    }
+
+    public ClauseName getClauseName() {
+        return clauseName;
+    }
+
+    public IpPrefix getIpPrefix() {
+        return ipPrefix;
+    }
+
+    public ClassifierName getClassifierName() {
+        return classifierName;
+    }
+
+    public RuleName getRuleName() {
+        return ruleName;
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/DataStoreHelper.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/DataStoreHelper.java
new file mode 100644 (file)
index 0000000..79573ed
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014 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.neutron.mapper.util;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+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.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+
+/**
+ * @author Martin Sunal
+ */
+public class DataStoreHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DataStoreHelper.class);
+
+    /**
+     * Reads data from datastore as synchrone call.
+     * @return {@link Optional#isPresent()} is {@code true} if reading was successful and data exists in datastore; {@link Optional#isPresent()} is {@code false} otherwise
+     */
+    public static <T extends DataObject> Optional<T> readFromDs(LogicalDatastoreType store, InstanceIdentifier<T> path, ReadTransaction rTx) {
+        CheckedFuture<Optional<T>, ReadFailedException> resultFuture = rTx.read(store, path);
+        try {
+            return resultFuture.checkedGet();
+        } catch (ReadFailedException e) {
+            LOG.warn("Read failed from DS.", e);
+            return Optional.absent();
+        }
+    }
+
+    /**
+     * Calls {@link WriteTransaction#submit()} on write transaction.
+     * @param wTx write transaction
+     * @return {@code true} if transaction commit was successful; {@code false} otherwise
+     */
+    public static boolean submitToDs(WriteTransaction wTx) {
+        CheckedFuture<Void, TransactionCommitFailedException> submitFuture = wTx.submit();
+        try {
+            submitFuture.checkedGet();
+            return true;
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Transaction commit failed to DS.", e);
+            return false;
+        }
+    }
+
+    /**
+     * If an element on the path exists in datastore the element is removed and returned as a result.
+     * {@link Optional#isPresent()} is {@code false} in case that element on path does not exist.
+     * @return removed element in {@link Optional#get()}; otherwise {@link Optional#absent()}
+     */
+    public static <T extends DataObject> Optional<T> removeIfExists(LogicalDatastoreType store, InstanceIdentifier<T> path,
+            ReadWriteTransaction rwTx) {
+        Optional<T> potentialResult = readFromDs(store, path, rwTx);
+        if (potentialResult.isPresent()) {
+            rwTx.delete(store, path);
+        }
+        return potentialResult;
+    }
+
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/IidFactory.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/IidFactory.java
new file mode 100644 (file)
index 0000000..ecb69ce
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2014 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.neutron.mapper.util;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.Mappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.EndpointGroupPairToContractMappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.NetworkMappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ContractKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomainKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.ClauseKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.SubjectKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.RuleKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstanceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class IidFactory {
+
+    private IidFactory() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static InstanceIdentifier<Tenant> tenantIid(TenantId id) {
+        return InstanceIdentifier.builder(Tenants.class).child(Tenant.class, new TenantKey(id)).build();
+    }
+
+    public static InstanceIdentifier<EndpointGroup> endpointGroupIid(TenantId tenantId, EndpointGroupId epgId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(EndpointGroup.class, new EndpointGroupKey(epgId))
+            .build();
+    }
+
+    public static InstanceIdentifier<Contract> contractIid(TenantId tenantId, ContractId contractId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Contract.class, new ContractKey(contractId))
+            .build();
+    }
+
+    public static InstanceIdentifier<Subject> subjectIid(TenantId tenantId, ContractId contractId,
+            SubjectName subjectName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Contract.class, new ContractKey(contractId))
+            .child(Subject.class, new SubjectKey(subjectName))
+            .build();
+    }
+
+    public static InstanceIdentifier<ProviderNamedSelector> providerNamedSelectorIid(TenantId tenantId,
+            EndpointGroupId epgId, SelectorName providerSelectorName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(EndpointGroup.class, new EndpointGroupKey(epgId))
+            .child(ProviderNamedSelector.class, new ProviderNamedSelectorKey(providerSelectorName))
+            .build();
+    }
+
+    public static InstanceIdentifier<ConsumerNamedSelector> consumerNamedSelectorIid(TenantId tenantId,
+            EndpointGroupId epgId, SelectorName consumerSelectorName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(EndpointGroup.class, new EndpointGroupKey(epgId))
+            .child(ConsumerNamedSelector.class, new ConsumerNamedSelectorKey(consumerSelectorName))
+            .build();
+    }
+
+    public static InstanceIdentifier<Clause> clauseIid(TenantId tenantId, ContractId contractId, ClauseName clauseName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Contract.class, new ContractKey(contractId))
+            .child(Clause.class, new ClauseKey(clauseName))
+            .build();
+    }
+
+    public static InstanceIdentifier<Rule> ruleIid(TenantId tenantId, ContractId contractId, SubjectName subjectName,
+            RuleName ruleName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Contract.class, new ContractKey(contractId))
+            .child(Subject.class, new SubjectKey(subjectName))
+            .child(Rule.class, new RuleKey(ruleName))
+            .build();
+    }
+
+    public static InstanceIdentifier<ActionInstance> actionInstanceIid(TenantId tenantId, ActionName actionName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(SubjectFeatureInstances.class)
+            .child(ActionInstance.class, new ActionInstanceKey(actionName))
+            .build();
+    }
+
+    public static InstanceIdentifier<ClassifierInstance> classifierInstanceIid(TenantId tenantId,
+            ClassifierName classifierName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(SubjectFeatureInstances.class)
+            .child(ClassifierInstance.class, new ClassifierInstanceKey(classifierName))
+            .build();
+    }
+
+    public static InstanceIdentifier<ClassifierRef> classifierRefIid(TenantId tenantId, ContractId contractId,
+            SubjectName subjectName, RuleName ruleName, ClassifierName classifierRefName) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Contract.class, new ContractKey(contractId))
+            .child(Subject.class, new SubjectKey(subjectName))
+            .child(Rule.class, new RuleKey(ruleName))
+            .child(ClassifierRef.class, new ClassifierRefKey(classifierRefName))
+            .build();
+    }
+
+    public static InstanceIdentifier<NetworkMapping> networkMappingIid(UniqueId networkId) {
+        return InstanceIdentifier.builder(Mappings.class)
+            .child(NetworkMappings.class)
+            .child(NetworkMapping.class, new NetworkMappingKey(networkId))
+            .build();
+    }
+
+    public static InstanceIdentifier<EndpointGroupPairToContractMapping> endpointGroupPairToContractMappingIid(
+            EndpointGroupId providerEpg, EndpointGroupId consumerEpg) {
+        return InstanceIdentifier.builder(Mappings.class)
+            .child(EndpointGroupPairToContractMappings.class)
+            .child(EndpointGroupPairToContractMapping.class,
+                    new EndpointGroupPairToContractMappingKey(consumerEpg, providerEpg))
+            .build();
+    }
+
+    public static InstanceIdentifier<L2FloodDomain> l2FloodDomainIid(TenantId tenantId, L2FloodDomainId l2FloodDomainId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(L2FloodDomain.class, new L2FloodDomainKey(l2FloodDomainId))
+            .build();
+    }
+
+    public static InstanceIdentifier<L2BridgeDomain> l2BridgeDomainIid(TenantId tenantId,
+            L2BridgeDomainId l2BridgeDomainId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(L2BridgeDomain.class, new L2BridgeDomainKey(l2BridgeDomainId))
+            .build();
+    }
+
+    public static InstanceIdentifier<L3Context> l3ContextIid(TenantId tenantId, L3ContextId l3ContextId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(L3Context.class, new L3ContextKey(l3ContextId))
+            .build();
+    }
+
+    public static InstanceIdentifier<Endpoint> endpointIid(L2BridgeDomainId l2Context, MacAddress macAddress) {
+        return InstanceIdentifier.builder(Endpoints.class)
+            .child(Endpoint.class, new EndpointKey(l2Context, macAddress))
+            .build();
+    }
+
+    public static InstanceIdentifier<EndpointL3> endpointL3Iid(L3ContextId l3Context, IpAddress ipAddress) {
+        return InstanceIdentifier.builder(Endpoints.class)
+            .child(EndpointL3.class, new EndpointL3Key(ipAddress, l3Context))
+            .build();
+    }
+
+    public static InstanceIdentifier<Subnet> subnetIid(TenantId tenantId, SubnetId subnetId) {
+        return InstanceIdentifier.builder(Tenants.class)
+            .child(Tenant.class, new TenantKey(tenantId))
+            .child(Subnet.class, new SubnetKey(subnetId))
+            .build();
+    }
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/MappingUtils.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/MappingUtils.java
new file mode 100644 (file)
index 0000000..0f26982
--- /dev/null
@@ -0,0 +1,90 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.util;
+
+import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstanceBuilder;
+
+import com.google.common.base.Optional;
+
+public final class MappingUtils {
+
+    public static final String NEUTRON_RULE__ = "neutron_rule__";
+    public static final String NEUTRON_NETWORK__ = "neutron_network__";
+    public static final String NEUTRON_ROUTER__ = "neutron_router__";
+    public static final String NEUTRON_GROUP__ = "neutron_group__";
+    public static final ActionInstance ACTION_ALLOW = new ActionInstanceBuilder().setName(
+            new ActionName(NEUTRON_RULE__ + "allow"))
+        .setActionDefinitionId(AllowAction.DEFINITION.getId())
+        .build();
+    public static final EndpointGroupId EPG_ANY_ID = new EndpointGroupId("aaaec0ce-dd5a-11e4-b9d6-1681e6b88ec1");
+    public static final EndpointGroupId EPG_DHCP_ID = new EndpointGroupId("ddd6cfe6-dfe5-11e4-8a00-1681e6b88ec1");
+    public static final EndpointGroupId EPG_ROUTER_ID = new EndpointGroupId("1118172e-cd84-4933-a35f-749f9a651de9");
+
+    private MappingUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance.");
+    }
+
+    public static ForwardingCtx createForwardingContext(TenantId tenantId, L2FloodDomainId l2FdId, ReadTransaction rTx) {
+        Optional<L2FloodDomain> potentialL2Fd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l2FloodDomainIid(tenantId, l2FdId), rTx);
+        if (!potentialL2Fd.isPresent()) {
+            return new ForwardingCtx(null, null, null);
+        }
+        L2BridgeDomainId l2BdId = potentialL2Fd.get().getParent();
+        if (l2BdId == null) {
+            return new ForwardingCtx(potentialL2Fd.get(), null, null);
+        }
+        Optional<L2BridgeDomain> potentialL2Bd = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rTx);
+        if (!potentialL2Bd.isPresent()) {
+            return new ForwardingCtx(potentialL2Fd.get(), null, null);
+        }
+        L3ContextId l3ContextId = potentialL2Bd.get().getParent();
+        if (l3ContextId == null) {
+            return new ForwardingCtx(potentialL2Fd.get(), potentialL2Bd.get(), null);
+        }
+        Optional<L3Context> potentialL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
+                IidFactory.l3ContextIid(tenantId, l3ContextId), rTx);
+        if (!potentialL3Context.isPresent()) {
+            return new ForwardingCtx(potentialL2Fd.get(), potentialL2Bd.get(), null);
+        }
+        return new ForwardingCtx(potentialL2Fd.get(), potentialL2Bd.get(), potentialL3Context.get());
+    }
+
+    public static final class ForwardingCtx {
+
+        private final L2FloodDomain l2FloodDomain;
+        private final L2BridgeDomain l2BridgeDomain;
+        private final L3Context l3Context;
+
+        private ForwardingCtx(L2FloodDomain l2Fd, L2BridgeDomain l2Bd, L3Context l3Context) {
+            this.l2FloodDomain = l2Fd;
+            this.l2BridgeDomain = l2Bd;
+            this.l3Context = l3Context;
+        }
+
+        public L2FloodDomain getL2FloodDomain() {
+            return l2FloodDomain;
+        }
+
+        public L2BridgeDomain getL2BridgeDomain() {
+            return l2BridgeDomain;
+        }
+
+        public L3Context getL3Context() {
+            return l3Context;
+        }
+
+    }
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/NeutronUtils.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/NeutronUtils.java
new file mode 100644 (file)
index 0000000..a55a481
--- /dev/null
@@ -0,0 +1,17 @@
+package org.opendaylight.groupbasedpolicy.neutron.mapper.util;
+
+public final class NeutronUtils {
+
+    public static final String EGRESS = "egress";
+    public static final String INGRESS = "ingress";
+    public static final String IPv6 = "IPv6";
+    public static final String IPv4 = "IPv4";
+    public static final String NULL = "null";
+    public static final String UDP = "udp";
+    public static final String TCP = "tcp";
+    public static final String ICMP = "icmp";
+
+    private NeutronUtils() {
+        throw new UnsupportedOperationException("Cannot create an instance.");
+    }
+}
diff --git a/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/Utils.java b/neutron-mapper/src/main/java/org/opendaylight/groupbasedpolicy/neutron/mapper/util/Utils.java
new file mode 100644 (file)
index 0000000..8f30ebb
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 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.neutron.mapper.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
+
+import com.google.common.base.Strings;
+import com.google.common.net.InetAddresses;
+
+/**
+ * @author Martin Sunal
+ */
+public class Utils {
+
+    private Utils() {}
+
+    /**
+     * This implementation does not use nameservice lookups (e.g. no DNS).
+     *
+     * @param cidr - format must be valid for regex in {@link Ipv4Prefix} or {@link Ipv6Prefix}
+     * @return the {@link IpPrefix} having the given cidr string representation
+     * @throws IllegalArgumentException - if the argument is not a valid CIDR string
+     */
+    public static IpPrefix createIpPrefix(String cidr) {
+        checkArgument(!Strings.isNullOrEmpty(cidr), "Cannot be null or empty.");
+        String[] ipAndPrefix = cidr.split("/");
+        checkArgument(ipAndPrefix.length == 2, "Bad format.");
+        InetAddress ip = InetAddresses.forString(ipAndPrefix[0]);
+        if (ip instanceof Inet4Address) {
+            return new IpPrefix(new Ipv4Prefix(cidr));
+        }
+        return new IpPrefix(new Ipv6Prefix(cidr));
+    }
+
+    /**
+     * This implementation does not use nameservice lookups (e.g. no DNS).
+     *
+     * @param ipAddress - format must be valid for regex in {@link Ipv4Address} or
+     *        {@link Ipv6Address}
+     * @return the {@link IpAddress} having the given ipAddress string representation
+     * @throws IllegalArgumentException - if the argument is not a valid IP address string
+     */
+    public static IpAddress createIpAddress(String ipAddress) {
+        checkArgument(!Strings.isNullOrEmpty(ipAddress), "Cannot be null or empty.");
+        InetAddress ip = InetAddresses.forString(ipAddress);
+        if (ip instanceof Inet4Address) {
+            return new IpAddress(new Ipv4Address(ipAddress));
+        }
+        return new IpAddress(new Ipv6Address(ipAddress));
+    }
+
+    public static String getStringIpPrefix(IpPrefix ipPrefix) {
+        if (ipPrefix.getIpv4Prefix() != null) {
+            return ipPrefix.getIpv4Prefix().getValue();
+        }
+        return ipPrefix.getIpv6Prefix().getValue();
+    }
+
+    public static String getStringIpAddress(IpAddress ipAddress) {
+        if (ipAddress.getIpv4Address() != null) {
+            return ipAddress.getIpv4Address().getValue();
+        }
+        return ipAddress.getIpv6Address().getValue();
+    }
+
+    public static boolean isHostInIpPrefix(IpAddress host, IpPrefix ipPrefix) {
+        String ipAddress = "";
+        int ipVersion = 0;
+        if (host.getIpv4Address() != null) {
+            ipAddress = host.getIpv4Address().getValue();
+            ipVersion = 4;
+        } else {
+            ipAddress = host.getIpv6Address().getValue();
+            ipVersion = 6;
+        }
+        String cidr = getStringIpPrefix(ipPrefix);
+
+        if (ipVersion == 4) {
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                return info.isInRange(ipAddress);
+            } catch (IllegalArgumentException e) {
+                return false;
+            }
+        }
+
+        if (ipVersion == 6) {
+            String[] parts = cidr.split("/");
+            try {
+                int length = Integer.parseInt(parts[1]);
+                byte[] cidrBytes = ((Inet6Address) InetAddress.getByName(parts[0])).getAddress();
+                byte[] ipBytes = ((Inet6Address) InetAddress.getByName(ipAddress)).getAddress();
+                int i;
+                for (i = 0; i < length; i++) { // offset is to ensure proper comparison
+                    if ((((cidrBytes[i / 8]) & 0x000000FF) & (1 << (7 - (i % 8)))) != (((ipBytes[i / 8]) & 0x000000FF) & (1 << (7 - (i % 8))))) {
+                        return false;
+                    }
+                }
+                return true;
+            } catch (UnknownHostException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    public static String normalizeUuid(String string) {
+        return string.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)",
+                "$1-$2-$3-$4-$5");
+    }
+
+}
diff --git a/neutron-mapper/src/main/yang/mapper.yang b/neutron-mapper/src/main/yang/mapper.yang
new file mode 100644 (file)
index 0000000..2918bc5
--- /dev/null
@@ -0,0 +1,66 @@
+module neutron-mapper {
+    yang-version 1;
+
+    namespace "urn:opendaylight:groupbasedpolicy:neutron-mapper";
+    prefix "gbp-neutron-mapper";
+
+    import gbp-common {prefix gbp-common;}
+    import endpoint {prefix gbp-endpoint;}
+    import ietf-inet-types {prefix inet;}
+
+    description 
+        "This module defines the mapping model between Neutron IDs and GBP IDs.";
+
+    revision "2015-02-23" {
+        description
+            "Initial revision.";
+    }
+
+    grouping tenant-id-fields {
+        leaf tenant-id {
+                description "A unique ID for the tenant";
+                mandatory true;
+                type gbp-common:tenant-id;
+        }
+    }
+
+    grouping endpoint-group-pair-fields {
+        leaf provider-epg-id {
+            type gbp-common:endpoint-group-id;
+        }
+        leaf consumer-epg-id {
+            type gbp-common:endpoint-group-id;
+        }
+        leaf contract-id {
+            type gbp-common:contract-id;
+        }
+    }
+
+    container mappings {
+        config false;
+        container network-mappings {
+            list network-mapping {
+                key network-id;
+                leaf network-id {
+                    description "A unique ID for the neutron network == gbp l2-flood-domain";
+                    type gbp-common:unique-id;
+                }
+                leaf l2-bridge-domain-id {
+                    description "A unique ID of l2-bridge-domain generated for neutron network";
+                    type gbp-common:l2-bridge-domain-id;
+                }
+                leaf l3-context-id {
+                    description "A unique ID of l3-context generated for neutron network";
+                    type gbp-common:l3-context-id;
+                }
+            }
+        }
+        container endpoint-group-pair-to-contract-mappings {
+            list endpoint-group-pair-to-contract-mapping {
+                key "provider-epg-id consumer-epg-id";
+                uses endpoint-group-pair-fields;
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/neutron-mapper/src/main/yang/neutron-mapper-impl.yang b/neutron-mapper/src/main/yang/neutron-mapper-impl.yang
new file mode 100644 (file)
index 0000000..2bc1066
--- /dev/null
@@ -0,0 +1,52 @@
+module neutron-mapper-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:neutron-mapper:impl";
+    prefix "neutron-mapper-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        neutron-mapper implementation.";
+
+    revision "2015-02-19" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of the service implementation as a module identity.
+    identity neutron-mapper-impl {
+        base config:module-type;
+
+        // Specifies the prefix for generated java classes.
+        config:java-name-prefix NeutronMapper;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+    augment "/config:modules/config:module/config:configuration" {
+        case neutron-mapper-impl {
+            when "/config:modules/config:module/config:type = 'neutron-mapper-impl'";
+
+            container data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-async-data-broker;
+                    }
+                }
+            }
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index fbb96a020fc23fa501ee734c5ef85767e425ffe6..2b17b6327fcf9c45be12e5241f2693fd95df85de 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -23,6 +23,8 @@
     <module>groupbasedpolicy-ofoverlay-config</module>
     <module>groupbasedpolicy-opflex-config</module>
     <module>groupbasedpolicy-openstackendpoint-config</module>
+    <module>neutron-mapper</module>
+    <module>neutron-mapper-config</module>
     <module>distribution-karaf</module>
     <module>features</module>
   </modules>
@@ -48,4 +50,3 @@
   </scm>
 
 </project>
-