Merge "L3: Add support for distributed arp responder and l3 forwarding"
authorDave Tucker <djt@redhat.com>
Thu, 4 Sep 2014 12:53:20 +0000 (12:53 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 4 Sep 2014 12:53:20 +0000 (12:53 +0000)
22 files changed:
features/ovs-sfc/pom.xml [new file with mode: 0644]
features/ovs-sfc/src/main/resources/features.xml [new file with mode: 0644]
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginV3IT.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/ovsdb/northbound/DatabaseResource.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/NodeResource.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/OvsdbRow.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/RowResource.java
northbound/src/main/java/org/opendaylight/ovsdb/northbound/TableResource.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/Activator.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/AbstractServiceInstance.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/OF13Provider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/EgressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/providers/openflow13/services/IngressAclService.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/Activator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/Constants.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EgressAclProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java [new file with mode: 0644]
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java [new file with mode: 0644]
plugin/src/main/java/org/opendaylight/ovsdb/plugin/impl/ConfigurationServiceImpl.java
pom.xml
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java

diff --git a/features/ovs-sfc/pom.xml b/features/ovs-sfc/pom.xml
new file mode 100644 (file)
index 0000000..ce0e666
--- /dev/null
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ /*
+  ~ * Copyright (C) 2014 Red Hat, Inc.
+  ~ *
+  ~ * 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
+  ~ *
+  ~ * Authors : Sam Hague
+  ~ */
+  -->
+
+<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.ovsdb</groupId>
+    <artifactId>commons</artifactId>
+    <version>1.2.0-SNAPSHOT</version>
+    <relativePath>../../commons/parent</relativePath>
+  </parent>
+  <artifactId>features-ovs-sfc</artifactId>
+  <name>OpenDaylight OVSDB OVS Service Function Chaining Karaf Features</name>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <properties>
+    <features.file>features.xml</features.file>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>features-openflow-nxm</artifactId>
+      <version>${openflowplugin.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>features-ovsdb</artifactId>
+      <version>${ovsdb.library.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-test</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <type>zip</type>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>plugin</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>ovssfc</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.sfc</groupId>
+      <artifactId>sfc-model</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <resources>
+      <resource>
+        <filtering>true</filtering>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>filter</id>
+            <goals>
+              <goal>resources</goal>
+            </goals>
+            <phase>generate-resources</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <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/${features.file}</file>
+                  <type>xml</type>
+                  <classifier>features</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <skip>${skip.karaf}</skip>
+          <systemPropertyVariables>
+            <karaf.distro.groupId>org.opendaylight.controller</karaf.distro.groupId>
+            <karaf.distro.artifactId>opendaylight-karaf-empty</karaf.distro.artifactId>
+            <karaf.distro.version>1.4.2-SNAPSHOT</karaf.distro.version>
+          </systemPropertyVariables>
+          <dependenciesToScan>
+           <dependency>org.opendaylight.yangtools:features-test</dependency>
+          </dependenciesToScan>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/ovsdb.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OVSDB_Integration:Main</url>
+   </scm>
+</project>
diff --git a/features/ovs-sfc/src/main/resources/features.xml b/features/ovs-sfc/src/main/resources/features.xml
new file mode 100644 (file)
index 0000000..5e07507
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+    <features name="ovsdb-${project.version}"
+          xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.controller/features-nsf/${nsf.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.ovsdb/features-openflow-nxm/${openflowplugin.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${ovsdb.library.version}/xml/features</repository>
+
+    <feature name="odl-ovsdb-ovssfc"
+             description="OpenDaylight :: OVSDB :: OVS Service Function Chaining"
+             version='${ovsdb.ovssfc.version}'>
+        <feature version="${ovsdb.plugin.version}">odl-ovsdb-plugin</feature>
+        <feature version="${openflowplugin.version}">odl-openflow-nxm-extensions</feature>
+        <feature version="${nsf.version}">odl-nsf-all</feature>
+        <bundle>mvn:org.opendaylight.sfc/sfc-model/${sfc-model.version}</bundle>
+        <bundle>mvn:org.opendaylight.ovsdb/ovssfc/${ovsdb.ovssfc.version}</bundle>
+    </feature>
+</features>
diff --git a/integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginV3IT.java b/integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginV3IT.java
new file mode 100644 (file)
index 0000000..84a2d0c
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2014 Red Hat, 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
+ *
+ * Authors : Madhu Venugopal
+ */
+package org.opendaylight.ovsdb.integrationtest.plugin;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperty;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.inject.Inject;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.ovsdb.integrationtest.ConfigurationBundles;
+import org.opendaylight.ovsdb.integrationtest.OvsdbIntegrationTestBase;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.plugin.api.Connection;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
+import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryListener;
+import org.opendaylight.ovsdb.plugin.api.OvsdbInventoryService;
+import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
+import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+
+@RunWith(PaxExam.class)
+public class OvsdbPluginV3IT extends OvsdbIntegrationTestBase {
+    private Logger log = LoggerFactory.getLogger(OvsdbPluginV3IT.class);
+    @Inject
+    private BundleContext bc;
+    private OvsdbConfigurationService ovsdbConfigurationService = null;
+    private String databaseName = "Open_vSwitch";
+
+    @Inject
+    private OvsdbInventoryService ovsdbInventoryService;
+
+    private Node node = null;
+    private OvsdbClient client = null;
+
+    // Configure the OSGi container
+    @Configuration
+    public Option[] config() {
+        return options(
+            //
+            systemProperty("logback.configurationFile").value(
+                    "file:" + PathUtils.getBaseDir()
+                    + "/src/test/resources/logback.xml"
+            ),
+            // To start OSGi console for inspection remotely
+            systemProperty("osgi.console").value("2401"),
+
+            propagateSystemProperty("ovsdbserver.ipaddress"),
+            propagateSystemProperty("ovsdbserver.port"),
+
+            ConfigurationBundles.controllerBundles(),
+            ConfigurationBundles.ovsdbLibraryBundles(),
+            ConfigurationBundles.ovsdbDefaultSchemaBundles(),
+            ConfigurationBundles.ovsdbPluginBundles(),
+            junitBundles()
+        );
+    }
+
+    private String stateToString(int state) {
+        switch (state) {
+        case Bundle.ACTIVE:
+            return "ACTIVE";
+        case Bundle.INSTALLED:
+            return "INSTALLED";
+        case Bundle.RESOLVED:
+            return "RESOLVED";
+        case Bundle.UNINSTALLED:
+            return "UNINSTALLED";
+        default:
+            return "Not CONVERTED";
+        }
+    }
+
+    @Before
+    public void areWeReady() throws InterruptedException {
+        assertNotNull(bc);
+        boolean debugit = false;
+        Bundle b[] = bc.getBundles();
+        for (Bundle element : b) {
+            int state = element.getState();
+            if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
+                log.info("Bundle:" + element.getSymbolicName() + " state:"
+                          + stateToString(state));
+                debugit = true;
+            }
+        }
+        if (debugit) {
+            log.debug("Do some debugging because some bundle is unresolved");
+        }
+
+        assertFalse(debugit);
+        try {
+            node = getPluginTestConnection();
+        } catch (Exception e) {
+            fail("Exception : "+e.getMessage());
+        }
+        this.ovsdbConfigurationService = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class, this);
+    }
+
+    @Test
+    public void apiTests() throws Exception {
+        Thread.sleep(5000);
+        OvsdbConnectionService
+                connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
+
+        // Check for the ovsdb Connection as seen by the Plugin layer
+        assertNotNull(connectionService.getNodes());
+        assertTrue(connectionService.getNodes().size() > 0);
+        Node node = connectionService.getNodes().get(0);
+        Connection connection = connectionService.getConnection(node);
+        OvsdbConnectionInfo connectionInfo = connection.getClient().getConnectionInfo();
+        String identifier = IDENTIFIER;
+        if (connectionInfo.getType().equals(OvsdbConnectionInfo.ConnectionType.PASSIVE)) {
+            identifier = connectionInfo.getRemoteAddress().getHostAddress()+":"+connectionInfo.getRemotePort();
+        }
+        assertEquals(Node.fromString("OVS|" + identifier), connectionService.getNodes().get(0));
+        System.out.println("Nodes = "+ connectionService.getNodes());
+        /*
+         * Test sequence :
+         * 1. Print Cache and Assert to make sure the bridge is not created yet.
+         * 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
+         * 3. Assert to make sure the bridge is created with a valid Uuid.
+         * 4. Delete the bridge & Assert to make sure the return status is success.
+         * 5. Assert to make sure the bridge is deleted
+         */
+
+        this.endToEndApiTest(connection, getOpenVSwitchTableUUID(connection));
+    }
+
+    @Test
+    public void testInventoryListeners() throws UnknownHostException {
+        DependencyManager dm = new DependencyManager(bc);
+
+        OvsdbInventoryListener listenerA = Mockito.mock(FakeListener.class);
+        OvsdbInventoryListener listenerB = Mockito.mock(FakeListener.class);
+
+        Component componentA = dm.createComponent();
+        componentA.setInterface(OvsdbInventoryListener.class.getName(), null);
+        componentA.setImplementation(listenerA);
+        dm.add(componentA);
+
+        Component componentB = dm.createComponent();
+        componentB.setInterface(OvsdbInventoryListener.class.getName(), null);
+        componentB.setImplementation(listenerB);
+        dm.add(componentB);
+
+        Node newNode = Node.fromString("OVS:10.10.10.10:65342");
+        InetAddress address = InetAddress.getByName("10.10.10.10");
+        int port = 65342;
+
+        // Trigger event
+        ovsdbInventoryService.notifyNodeAdded(newNode, address, port);
+
+        Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode, address, port);
+        Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode, address, port);
+
+        dm.remove(componentA);
+        dm.remove(componentB);
+
+    }
+
+    public void endToEndApiTest(Connection connection, String parentUuid) throws Exception {
+        // 1. Print Cache and Assert to make sure the bridge is not created yet.
+        printCache();
+
+        // 2. Create a bridge with a valid parent_uuid & Assert to make sure the return status is success.
+        StatusWithUuid status = insertBridge(connection, parentUuid);
+        assertTrue(status.isSuccess());
+
+        Thread.sleep(2000);
+
+        // 3. Assert to make sure the bridge is created with a valid Uuid.
+        printCache();
+        Bridge bridge = connection.getClient().getTypedRowWrapper(Bridge.class, null);
+        Row bridgeRow = ovsdbConfigurationService.getRow(node, databaseName, bridge.getSchema().getName(), status.getUuid());
+        assertNotNull(bridgeRow);
+        bridge = connection.getClient().getTypedRowWrapper(Bridge.class, bridgeRow);
+        System.out.println("Bridge UUID "+bridge.getUuid()+" Status Uuid "+status.getUuid());
+        assertEquals(bridge.getUuid(), status.getUuid());
+
+        bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
+        bridge.setDatapathType("netdev");
+        try {
+            ovsdbConfigurationService.updateRow(node, databaseName, bridge.getSchema().getName(), status.getUuid(), bridge.getRow(), false);
+        } catch (Exception e) {
+            fail("Failed to updated Bridge "+e.getMessage());
+        }
+
+        // 4. Delete the bridge & Assert to make sure the return status is success.
+        try {
+            ovsdbConfigurationService.deleteRow(node, databaseName, bridge.getSchema().getName(), null, new UUID(parentUuid) ,null, status.getUuid());
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        Thread.sleep(2000);
+
+        // 5. Assert to make sure the bridge is deleted
+        bridgeRow = ovsdbConfigurationService.getRow(node, databaseName, bridge.getSchema().getName(), status.getUuid());
+        assertNull(bridgeRow);
+    }
+
+    public StatusWithUuid insertBridge(Connection connection, String parentUuid) throws Exception {
+        Bridge bridge = connection.getClient().createTypedRowWrapper(Bridge.class);
+        bridge.setName("br_test1");
+        bridge.setStatus(ImmutableMap.of("key", "value"));
+        bridge.setFloodVlans(Sets.newHashSet(34L));
+        try {
+        Row<GenericTableSchema> row = ovsdbConfigurationService.insertTree(node, databaseName, bridge.getSchema().getName(), new UUID(parentUuid), bridge.getRow());
+        bridge = connection.getClient().getTypedRowWrapper(Bridge.class, row);
+        return new StatusWithUuid(StatusCode.SUCCESS, bridge.getUuid());
+        } catch (Exception e) {
+            return new StatusWithUuid(StatusCode.INTERNALERROR);
+        }
+    }
+
+    public String getOpenVSwitchTableUUID(Connection connection) throws Exception {
+        OpenVSwitch openVSwitch = connection.getClient().getTypedRowWrapper(OpenVSwitch.class, null);
+        ConcurrentMap<UUID, Row<GenericTableSchema>> rows = ovsdbConfigurationService.getRows(node, databaseName, openVSwitch.getSchema().getName());
+        if (rows == null || rows.size() == 0) return null;
+        return rows.keySet().toArray()[0].toString();
+    }
+
+    public void printCache() throws Exception {
+        List<String> tables = ovsdbConfigurationService.getTables(node, databaseName);
+        System.out.println("Tables = "+tables);
+        assertNotNull(tables);
+        for (String table : tables) {
+            System.out.println("Table "+table);
+            ConcurrentMap<UUID, Row<GenericTableSchema>> rows = ovsdbConfigurationService.getRows(node, databaseName, table);
+            System.out.println(rows);
+        }
+    }
+
+    public class FakeListener implements OvsdbInventoryListener {
+
+        @Override
+        public void nodeAdded(Node node, InetAddress address, int port) {
+
+        }
+
+        @Override
+        public void nodeRemoved(Node node) {
+
+        }
+
+        @Override
+        public void rowAdded(Node node, String tableName, String uuid, Row row) {
+
+        }
+
+        @Override
+        public void rowUpdated(Node node, String tableName, String uuid, Row old, Row row) {
+
+        }
+
+        @Override
+        public void rowRemoved(Node node, String tableName, String uuid, Row row, Object context) {
+
+        }
+    }
+
+}
index d49d882e73ac23ae7620fb8c440e42fc470d7029..caf03d2f07da58c9746eba8f7b2372c538a44e70 100644 (file)
@@ -1,5 +1,7 @@
 package org.opendaylight.ovsdb.northbound;
 
+import java.util.List;
+
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -7,33 +9,85 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
  * Northbound interface for OVSDB Databases
  */
 public class DatabaseResource {
 
     String nodeId;
-
+    ObjectMapper objectMapper;
     DatabaseResource(String id) {
         this.nodeId = id;
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
+
+    private DatabaseSchema getDatabaseSchema (String databaseName) {
+        String csDatabaseName = this.caseSensitiveDatabaseName(databaseName);
+        OvsdbClient client = NodeResource.getOvsdbConnection(nodeId, this);
+        return client.getDatabaseSchema(csDatabaseName);
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     public Response getDatabases(){
-        return Response.noContent().build();
+        OvsdbClient client = NodeResource.getOvsdbConnection(nodeId, this);
+        try {
+            List<String> databases = client.getDatabases().get();
+            if (databases == null) {
+                return Response.noContent().build();
+            }
+            String response = objectMapper.writeValueAsString(databases);
+            return Response.status(Response.Status.OK)
+                    .entity(response)
+                    .build();
+        } catch (Exception e) {
+            throw new InternalServerErrorException("Failed due to exception " + e.getMessage());
+        }
     }
 
     @GET
     @Path("{name}")
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getDatabases(@PathParam("name") String name){
-        return Response.noContent().build();
+    public Response getDatabases(@PathParam("name") String name) throws JsonProcessingException {
+        DatabaseSchema dbSchema = this.getDatabaseSchema(name);
+        String response = objectMapper.writeValueAsString(dbSchema);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @Path("{name}/table")
     public TableResource getDatabaseTables(@PathParam("name") String name){
-        return new TableResource(nodeId, name);
+        String csDatabaseName = this.caseSensitiveDatabaseName(name);
+        return new TableResource(nodeId, csDatabaseName);
     }
 
+    private String caseSensitiveDatabaseName (String ciDatabaseName) {
+        Node node = Node.fromString(nodeId);
+        OvsdbConnectionService connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
+        OvsdbClient client = connectionService.getConnection(node).getClient();
+
+        try {
+            List<String> databases = client.getDatabases().get();
+            if (databases == null) return ciDatabaseName;
+            for (String csDatabaseName : databases) {
+                if (csDatabaseName.equalsIgnoreCase(ciDatabaseName)) return csDatabaseName;
+            }
+            return ciDatabaseName;
+        } catch (Exception e) {
+            return ciDatabaseName;
+        }
+    }
 }
index c6491d89d6fc168f18b783ec9d4fdc622fb75543..d80658b456e8e14b70a32a60270cea0cc8b2d2c7 100644 (file)
@@ -1,6 +1,7 @@
 package org.opendaylight.ovsdb.northbound;
 
 import java.io.InputStream;
+import java.util.List;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -13,15 +14,62 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
+import org.opendaylight.ovsdb.plugin.api.Connection;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Lists;
+
 /**
  * Northbound Interface for OVSDB Nodes
  */
 public class NodeResource {
+    ObjectMapper objectMapper;
+    public NodeResource () {
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
+
+    public static OvsdbClient getOvsdbConnection(String nodeId, Object bundleClassRef) {
+        Node node = Node.fromString(nodeId);
+        if (node == null) {
+            throw new ResourceNotFoundException("Node "+nodeId+" not found");
+        }
+        OvsdbConnectionService connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, bundleClassRef);
+        Connection connection = connectionService.getConnection(node);
+        if (connection == null) {
+            throw new ResourceNotFoundException("Connection for "+nodeId+" not available");
+        }
+        OvsdbClient client = connectionService.getConnection(node).getClient();
+        if (client == null) {
+            throw new ResourceNotFoundException("No Ovsdb Client to handle Node "+nodeId);
+        }
+        return client;
+    }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getNodes(){
-        return Response.noContent().build();
+    public Response getNodes() throws JsonProcessingException {
+        OvsdbConnectionService connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
+        List<Node> nodes = connectionService.getNodes();
+        if (nodes == null) return Response.noContent().build();
+
+        List<String> nodeIds = Lists.newArrayList();
+        for (Node node : nodes) {
+            nodeIds.add(node.toString());
+        }
+
+        String response = objectMapper.writeValueAsString(nodeIds);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @POST
@@ -34,8 +82,17 @@ public class NodeResource {
     @GET
     @Path("{id}")
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getNode(@PathParam("id") String id){
-        return Response.noContent().build();
+    public Response getNode(@PathParam("id") String id) throws JsonProcessingException {
+        OvsdbConnectionService connectionService = (OvsdbConnectionService)ServiceHelper.getGlobalInstance(OvsdbConnectionService.class, this);
+        OvsdbClient client = NodeResource.getOvsdbConnection(id, this);
+        if (client == null) {
+            throw new ResourceNotFoundException("Node "+id+" not found");
+        }
+        OvsdbConnectionInfo connectionInfo = client.getConnectionInfo();
+        String response = objectMapper.writeValueAsString(connectionInfo);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @PUT
index ca4a56b9f259ff2eaad277ee0d9fd44906231d87..fc4b827767a98a496e16cad94b7b629a990e3bed 100644 (file)
@@ -13,8 +13,6 @@ import java.io.IOException;
 import java.util.Iterator;
 import java.util.concurrent.ExecutionException;
 
-import javax.xml.bind.annotation.XmlElement;
-
 import org.opendaylight.ovsdb.lib.OvsdbClient;
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
@@ -24,18 +22,17 @@ import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
-@Deprecated
 public class OvsdbRow {
     private static final String PARENTUUID = "parent_uuid";
+    private static final String PARENTTABLE = "parent_table";
+    private static final String PARENTCOLUMN = "parent_column";
     private static final String ROW = "row";
 
-    @XmlElement(name=PARENTUUID)
-    String parentUuid;
-
-    String tableName;
-
-    @XmlElement(name=ROW)
-    Row<GenericTableSchema> row;
+    private String parentUuid;
+    private String parentTable;
+    private String parentColumn;
+    private String tableName;
+    private Row<GenericTableSchema> row;
 
     public OvsdbRow() {
     }
@@ -46,11 +43,27 @@ public class OvsdbRow {
         this.row = row;
     }
 
+    public OvsdbRow(String parentTable, String parentUuid, String parentColumn, String tableName, Row<GenericTableSchema> row) {
+        this.parentTable = parentTable;
+        this.parentColumn = parentColumn;
+        this.parentUuid = parentUuid;
+        this.tableName = tableName;
+        this.row = row;
+    }
+
     public static OvsdbRow fromJsonNode(OvsdbClient client, String dbName, JsonNode json) {
         JsonNode parentUuidNode = json.get(PARENTUUID);
         String parentUuid = null;
         if (parentUuidNode != null) parentUuid = parentUuidNode.asText();
 
+        JsonNode parentTableNode = json.get(PARENTTABLE);
+        String parentTable = null;
+        if (parentTableNode != null) parentTable = parentTableNode.asText();
+
+        JsonNode parentColumnNode = json.get(PARENTCOLUMN);
+        String parentColumn = null;
+        if (parentColumnNode != null) parentColumn = parentColumnNode.asText();
+
         JsonNode rowNode = json.get(ROW);
         if (rowNode == null) return null;
         for(Iterator<String> fieldNames = rowNode.fieldNames(); fieldNames.hasNext();) {
@@ -62,7 +75,7 @@ public class OvsdbRow {
                 e.printStackTrace();
                 return null;
             }
-            return new OvsdbRow(parentUuid, tableName, row);
+            return new OvsdbRow(parentTable, parentUuid, parentColumn, tableName, row);
         }
         return null;
     }
@@ -73,10 +86,18 @@ public class OvsdbRow {
         return schema.createRow((ObjectNode)rowJson);
     }
 
+    public String getParentTable() {
+        return parentTable;
+    }
+
     public String getParentUuid() {
         return parentUuid;
     }
 
+    public String getParentColumn() {
+        return parentColumn;
+    }
+
     public String getTableName() {
         return tableName;
     }
@@ -84,10 +105,4 @@ public class OvsdbRow {
     public Row<GenericTableSchema> getRow() {
         return row;
     }
-
-    @Override
-    public String toString() {
-        return "OVSDBRow [parentUuid=" + parentUuid + ", tableName="
-                + tableName + ", row=" + row + "]";
-    }
 }
index f61b06c373499cb403ff97609cc9009b492ab3f0..148d90eb7605842e061ea140960f49b615105b96 100644 (file)
@@ -1,6 +1,10 @@
 package org.opendaylight.ovsdb.northbound;
 
+import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Map;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -13,6 +17,23 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.plugin.api.OvsVswitchdSchemaConstants;
+import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
  * Northbound interface for OVSDB Rows
  */
@@ -20,48 +41,144 @@ public class RowResource {
 
     String nodeId;
     String databaseName;
-    String rowName;
+    String tableName;
+    ObjectMapper objectMapper;
 
-    public RowResource(String nodeId, String databaseName, String rowName) {
+    public RowResource(String nodeId, String databaseName, String tableName) {
         this.nodeId = nodeId;
         this.databaseName = databaseName;
-        this.rowName = rowName;
+        this.tableName = tableName;
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    }
+
+    private OvsdbRow getOvsdbRow (InputStream stream) throws IOException {
+        StringBuilder rowNodeStrBuilder = new StringBuilder();
+        BufferedReader in = new BufferedReader(new InputStreamReader(stream));
+        String line = null;
+        while ((line = in.readLine()) != null) {
+            rowNodeStrBuilder.append(line);
+        }
+        JsonNode jsonNode = objectMapper.readTree(rowNodeStrBuilder.toString());
+        OvsdbClient client = NodeResource.getOvsdbConnection(nodeId, this);
+        return OvsdbRow.fromJsonNode(client, OvsVswitchdSchemaConstants.DATABASE_NAME, jsonNode);
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getRows(){
-        return Response.noContent().build();
+    public Response getRows() throws JsonProcessingException {
+        OvsdbConfigurationService
+                ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
+                                                                                            this);
+        if (ovsdbTable == null) {
+            throw new ServiceUnavailableException("Ovsdb ConfigurationService " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Node node = Node.fromString(nodeId);
+        Map<UUID,Row<GenericTableSchema>> rows = null;
+        try {
+            rows = ovsdbTable.getRows(node, databaseName, tableName);
+        } catch (Exception e) {
+            throw new BadRequestException(e.getMessage());
+        }
+        String response = objectMapper.writeValueAsString(rows);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createRow(InputStream stream) {
-        return Response.noContent().build();
+    public Response createRow(InputStream stream) throws IOException {
+        Node node = Node.fromString(nodeId);
+        OvsdbRow localRow = this.getOvsdbRow(stream);
+        if (localRow == null) {
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+        OvsdbConfigurationService
+        ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
+                                                                                    this);
+        if (ovsdbTable == null) {
+            throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Row row = ovsdbTable.insertTree(node, OvsVswitchdSchemaConstants.DATABASE_NAME, tableName,
+                localRow.getParentTable(), new UUID(localRow.getParentUuid()), localRow.getParentColumn(),
+                localRow.getRow());
+        String response = objectMapper.writeValueAsString(row);
+        return Response.status(Response.Status.CREATED)
+                .entity(response)
+                .build();
     }
 
     @GET
     @Path("{id}")
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getRowDetails(@PathParam("id") String id){
-        return Response.noContent().build();
+    public Response getRowDetails(@PathParam("id") String id) throws JsonProcessingException {
+        OvsdbConfigurationService
+        ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
+                                                                                    this);
+        if (ovsdbTable == null) {
+            throw new ServiceUnavailableException("Ovsdb ConfigurationService " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Node node = Node.fromString(nodeId);
+        Row<GenericTableSchema> row = null;
+        try {
+            row = ovsdbTable.getRow(node, databaseName, tableName, new UUID(id));
+        } catch (Exception e) {
+            throw new BadRequestException(e.getMessage());
+        }
+        String response = objectMapper.writeValueAsString(row);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @PUT
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updateRow(@PathParam("id") String id){
-        return Response.noContent().build();
+    public Response updateRow(@PathParam("id") String id, InputStream stream) throws IOException{
+        Node node = Node.fromString(nodeId);
+        OvsdbRow localRow = this.getOvsdbRow(stream);
+        if (localRow == null) {
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+        OvsdbConfigurationService ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
+                                                                                    this);
+        if (ovsdbTable == null) {
+            throw new ServiceUnavailableException("OVS Configuration Service " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Row<GenericTableSchema> row = ovsdbTable.updateRow(node, databaseName, tableName, new UUID(id), localRow.getRow(), true);
+        String response = objectMapper.writeValueAsString(row);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @DELETE
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response deleteRow(@PathParam("id") String id){
-        return Response.noContent().build();
-    }
+        OvsdbConfigurationService
+        ovsdbTable = (OvsdbConfigurationService)ServiceHelper.getGlobalInstance(OvsdbConfigurationService.class,
+                                                                                    this);
+        if (ovsdbTable == null) {
+            throw new ServiceUnavailableException("Ovsdb ConfigurationService " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
 
+        Node node = Node.fromString(nodeId);
+        try {
+            ovsdbTable.deleteRow(node, databaseName, tableName, new UUID(id));
+        } catch (Exception e) {
+            throw new BadRequestException(e.getMessage());
+        }
+        return Response.status(Response.Status.OK)
+                .build();
 
+    }
 }
index 8620516a907fc463639cf33eb0efa8a55eeb365d..c5501b3a7d52758b265e5d15cc1fabc2d7bd8e17 100644 (file)
@@ -1,5 +1,7 @@
 package org.opendaylight.ovsdb.northbound;
 
+import java.util.Set;
+
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -7,30 +9,63 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
+import org.opendaylight.ovsdb.lib.schema.TableSchema;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
  * Northbound interface for OVSDB tables
  */
 public class TableResource {
-
+    ObjectMapper objectMapper;
     String databaseName;
     String nodeId;
 
     TableResource(String nodeId, String databaseName){
         this.nodeId = nodeId;
         this.databaseName = databaseName;
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+    }
+
+    private DatabaseSchema getDatabaseSchema (String databaseName) {
+        OvsdbClient client = NodeResource.getOvsdbConnection(nodeId, this);
+        return client.getDatabaseSchema(databaseName);
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getTables(){
-        return Response.noContent().build();
+    public Response getTables() throws JsonProcessingException {
+        DatabaseSchema dbSchema = this.getDatabaseSchema(databaseName);
+        if (dbSchema == null) {
+            return Response.noContent().build();
+        }
+        String response = objectMapper.writeValueAsString(dbSchema.getTables());
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @GET
     @Path("{name}")
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getTableDetails(@PathParam("name") String name){
-        return Response.noContent().build();
+    public Response getTableDetails(@PathParam("name") String name) throws JsonProcessingException {
+        String csTableName = this.caseSensitiveTableName(databaseName, name);
+        DatabaseSchema dbSchema = this.getDatabaseSchema(databaseName);
+        if (dbSchema == null) {
+            return Response.noContent().build();
+        }
+        TableSchema<GenericTableSchema> tableSchema = dbSchema.table(csTableName, GenericTableSchema.class);
+        String response = objectMapper.writeValueAsString(tableSchema);
+        return Response.status(Response.Status.OK)
+                .entity(response)
+                .build();
     }
 
     @Path("{name}/row")
@@ -38,4 +73,18 @@ public class TableResource {
         return new RowResource(nodeId, databaseName, name);
     }
 
+    private String caseSensitiveTableName (String databaseName, String ciTableName) {
+        DatabaseSchema dbSchema = this.getDatabaseSchema(databaseName);
+        if (dbSchema == null) {
+            return ciTableName;
+        }
+        Set<String> tables = dbSchema.getTables();
+        if (tables == null) {
+            return ciTableName;
+        }
+        for (String tableName : tables) {
+            if (tableName.equalsIgnoreCase(ciTableName)) return tableName;
+        }
+        return ciTableName;
+    }
 }
index 8638b34b5ae43d4e6ba6804869a4dde43a096891..b63e82949a137c6988141ee272e7c59671689c76 100644 (file)
@@ -20,11 +20,14 @@ import org.opendaylight.controller.switchmanager.ISwitchManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.InboundNatProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.L3ForwardingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OutboundNatProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow10.OF10Provider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
@@ -160,9 +163,14 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency()
                           .setService(TenantNetworkManager.class)
                           .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(SecurityServicesManager.class)
+                    .setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConfigurationService.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbConnectionService.class).setRequired(true));
             c.add(createServiceDependency().setService(MdsalConsumer.class).setRequired(true));
+            c.add(createServiceDependency().setService(IngressAclProvider.class).setRequired(true));
+            c.add(createServiceDependency().setService(EgressAclProvider.class).setRequired(true));
         }
 
         if (imp.equals(PipelineOrchestratorImpl.class)) {
@@ -172,10 +180,10 @@ public class Activator extends ComponentActivatorAbstractBase {
                            .setCallbacks("registerService", "unregisterService"));
         }
 
-        if (AbstractServiceInstance.class.isAssignableFrom((Class)imp)) {
+        if (AbstractServiceInstance.class.isAssignableFrom((Class) imp)) {
             c.add(createServiceDependency()
-                    .setService(PipelineOrchestrator.class)
-                    .setRequired(true));
+                          .setService(PipelineOrchestrator.class)
+                          .setRequired(true));
             c.add(createServiceDependency().setService(MdsalConsumer.class).setRequired(true));
         }
 
@@ -206,7 +214,8 @@ public class Activator extends ComponentActivatorAbstractBase {
             Properties properties = new Properties();
             properties.put(AbstractServiceInstance.SERVICE_PROPERTY, Service.INGRESS_ACL);
             properties.put(Constants.PROVIDER_NAME_PROPERTY, OF13Provider.NAME);
-            c.setInterface(AbstractServiceInstance.class.getName(), properties);
+            c.setInterface(new String[]{AbstractServiceInstance.class.getName(),
+                                        IngressAclProvider.class.getName()}, properties);
         }
 
         if (imp.equals(LoadBalancerService.class)) {
@@ -246,11 +255,12 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.setInterface(AbstractServiceInstance.class.getName(), properties);
         }
 
-        if (imp.equals(IngressAclService.class)) {
+        if (imp.equals(EgressAclService.class)) {
             Properties properties = new Properties();
-            properties.put(AbstractServiceInstance.SERVICE_PROPERTY, Service.INGRESS_ACL);
+            properties.put(AbstractServiceInstance.SERVICE_PROPERTY, Service.EGRESS_ACL);
             properties.put(Constants.PROVIDER_NAME_PROPERTY, OF13Provider.NAME);
-            c.setInterface(AbstractServiceInstance.class.getName(), properties);
+            c.setInterface(new String[]{AbstractServiceInstance.class.getName(),
+                                        EgressAclProvider.class.getName()}, properties);
         }
 
         if (imp.equals(OutboundNatService.class)) {
index 9fdc6fb3cb17b7c57b9d59c697a6f45f25eb6ce0..efc39c0a6666fb1085388740a0f2dc39c237f9d3 100644 (file)
@@ -120,7 +120,7 @@ public abstract class AbstractServiceInstance implements OpendaylightInventoryLi
         thread.start();
     }
 
-    private NodeBuilder createNodeBuilder(String nodeId) {
+    public NodeBuilder createNodeBuilder(String nodeId) {
         NodeBuilder builder = new NodeBuilder();
         builder.setId(new NodeId(nodeId));
         builder.setKey(new NodeKey(builder.getId()));
index 6483858665486398a5990da3caa5826c46233d65..b46bf3c58f7a356b5fc228eabe441aae54c94861 100644 (file)
@@ -9,8 +9,13 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+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.ReadWriteTransaction;
@@ -18,25 +23,29 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
-import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
-import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
-import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
 import org.opendaylight.ovsdb.plugin.api.StatusWithUuid;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
 import org.opendaylight.ovsdb.schema.openvswitch.Port;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 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.action.types.rev131112.action.action.GroupActionCase;
@@ -84,19 +93,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 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.collect.Lists;
 import com.google.common.collect.Maps;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
+import com.google.common.util.concurrent.CheckedFuture;
 
 /**
  * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
@@ -116,6 +120,9 @@ public class OF13Provider implements NetworkingProvider {
     private volatile OvsdbConfigurationService ovsdbConfigurationService;
     private volatile OvsdbConnectionService connectionService;
     private volatile MdsalConsumer mdsalConsumer;
+    private volatile SecurityServicesManager securityServicesManager;
+    private volatile IngressAclProvider ingressAclProvider;
+    private volatile EgressAclProvider egressAclProvider;
 
     public static final String NAME = "OF13Provider";
 
@@ -822,7 +829,21 @@ public class OF13Provider implements NetworkingProvider {
             if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
                 logger.debug("Program local vlan rules for interface {}", intf.getName());
                 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
-            } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
+            }
+            /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
+            if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
+                    (NetworkHandler.NETWORK_TYPE_VXLAN)) && securityServicesManager.isPortSecurityReady(intf)) {
+                logger.debug("Neutron port has a Port Security Group");
+                /* Retrieve the security group UUID from the Neutron Port */
+                NeutronSecurityGroup securityGroupInPort = securityServicesManager.getSecurityGroupInPort(intf);
+                logger.debug("Program Local rules for networkType: {} does contain a Port Security Group: {} " +
+                        "to be installed on DPID: {}", networkType, securityGroupInPort, dpid);
+                ingressAclProvider.programPortSecurityACL(node, dpid, segmentationId, attachedMac, localPort,
+                        securityGroupInPort);
+                egressAclProvider.programPortSecurityACL(node, dpid, segmentationId, attachedMac, localPort,
+                                                         securityGroupInPort);
+            }
+            else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
                        networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
                 logger.debug("Program local bridge rules for interface {}", intf.getName());
                 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
index 2c0b3c4dd51b0214afaea6f5f1ac4485818d8f56..ceaf38037717e1668ccb73cc6104418452f8c289 100644 (file)
@@ -9,10 +9,40 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+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.PortNumber;
+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.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+
+import com.google.common.collect.Lists;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.List;
+
+public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider {
+
+    static final Logger logger = LoggerFactory.getLogger(EgressAclService.class);
 
-public class EgressAclService extends AbstractServiceInstance {
     public EgressAclService() {
         super(Service.EGRESS_ACL);
     }
@@ -21,8 +51,427 @@ public class EgressAclService extends AbstractServiceInstance {
         super(service);
     }
 
+
     @Override
     public boolean isBridgeInPipeline (String nodeId) {
         return true;
     }
-}
\ No newline at end of file
+
+    @Override
+    public void programPortSecurityACL(Node node, Long dpid, String segmentationId, String attachedMac, long localPort,
+                                       NeutronSecurityGroup securityGroup) {
+
+        logger.trace("programLocalBridgeRulesWithSec neutronSecurityGroup: {} ", securityGroup);
+        List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
+        /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
+        for (NeutronSecurityRule portSecurityRule : portSecurityList) {
+            /**
+             * Neutron Port Security ACL "egress" and "IPv4"
+             *
+             * Check that the base conditions for flow based Port Security are true:
+             * Port Security Rule Direction ("egress") and Protocol ("IPv4")
+             * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
+             * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
+             *
+             */
+            if (portSecurityRule.getSecurityRuleEthertype().equalsIgnoreCase("IPv4") &&
+                portSecurityRule.getSecurityRuleDirection().equalsIgnoreCase("egress")) {
+                logger.debug("Egress IPV4 ACL  Port Security Rule: {} ", portSecurityRule);
+                // ToDo: Implement Port Range
+
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                     !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                             .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug(
+                            "Rule #1 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                                            Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
+                                            true);
+                    egressACLTcpPortWithPrefix(dpid, segmentationId,
+                                               attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                                               portSecurityRule.getSecurityRuleRemoteIpPrefix(),
+                                               Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                     !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                             .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug(
+                            "Rule #2 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                                            Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
+                                            true);
+                    egressACLTcpPortWithPrefix(dpid, segmentationId,
+                                               attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                                               portSecurityRule.getSecurityRuleRemoteIpPrefix(),
+                                               Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug(
+                            "Rule #3 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PREFIX_MATCH_PRIORITY_DROP,
+                                            true);
+                    egressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
+                                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (False), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                     !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                             .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug(
+                            "Rule #4 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PREFIX_MATCH_PRIORITY_DROP, true);
+                    egressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
+                                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (False)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug(
+                            "Rule #5 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PORT_MATCH_PRIORITY_DROP,
+                                            true);
+                    egressACLTcpSyn(dpid, segmentationId,
+                                    attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                                    Constants.PROTO_PORT_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (False)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug(
+                            "Rule #6 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                                            Constants.PROTO_PORT_MATCH_PRIORITY_DROP, true);
+                    egressACLTcpSyn(dpid, segmentationId, attachedMac, true,
+                                    portSecurityRule.getSecurityRulePortMin(), Constants.PROTO_PORT_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (False or 0.0.0.0/0)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                    String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                    ((String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) ||
+                     String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                             .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug(
+                            "Rule #7 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    // No need to drop until UDP/ICMP are implemented
+                    // egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, PROTO_MATCH_PRIORITY_DROP, true);
+                    egressAllowProto(dpid, segmentationId, attachedMac, true,
+                                     portSecurityRule.getSecurityRuleProtocol(), Constants.PROTO_MATCH_PRIORITY);
+                    continue;
+                }
+                logger.debug("ACL Match combination not found for rule: {}", portSecurityRule);
+            }
+        }
+    }
+
+    public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
+                                        int priority, boolean write) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createSmacTcpPortWithFlagMatch(matchBuilder,
+                                                                       attachedMac, Constants.TCP_SYN, segmentationId).build());
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+
+        String flowId = "TCP_Syn_Egress_Default_Drop_" + attachedMac;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(priority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructions = Lists.newArrayList();
+
+            InstructionUtils.createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void egressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac, boolean write,
+                                           Integer securityRulePortMin, String securityRuleIpPrefix, Integer protoPortPrefixMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        PortNumber tcpPort = new PortNumber(securityRulePortMin);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
+
+        flowBuilder.setMatch(MatchUtils
+                                     .createSmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
+                                                                         tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix).build());
+
+        logger.debug(" MatchBuilder contains:  {}", flowBuilder.getMatch());
+        String flowId = "UcastEgress_" + segmentationId + "_" + attachedMac +
+                        securityRulePortMin + securityRuleIpPrefix;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortPrefixMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+
+    public void egressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
+                                 String securityRuleProtcol, Integer protoMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils
+                                     .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null).build());
+        flowBuilder.setMatch(MatchUtils
+                                     .createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+
+        logger.debug("MatchBuilder contains:  {}", flowBuilder.getMatch());
+        String flowId = "EgressAllProto_" + segmentationId + "_" +
+                        attachedMac + "_AllowEgressTCPSyn_" + securityRuleProtcol;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void egressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
+                                        boolean write, String securityRuleIpPrefix, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId))
+                                     .build());
+        if (securityRuleIpPrefix != null) {
+            flowBuilder.setMatch(MatchUtils
+                                         .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix)
+                                         .build());
+        } else {
+            flowBuilder.setMatch(MatchUtils
+                                         .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null)
+                                         .build());
+        }
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Egress_Proto_ACL" + segmentationId + "_" +
+                        attachedMac + "_Permit_" + securityRuleIpPrefix;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+    public void egressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
+                                Integer securityRulePortMin, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        PortNumber tcpPort = new PortNumber(securityRulePortMin);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createSmacTcpSyn(matchBuilder, attachedMac, tcpPort,
+                                                         Constants.TCP_SYN, segmentationId).build());
+
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Ucast_this.getTable()" + segmentationId + "_" + attachedMac + securityRulePortMin;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+}
index b77643a713edbdfae7c81936b127c9d837a72a44..ad2e37a9f474a992b85cbb074670bebebf1e2864 100644 (file)
@@ -9,10 +9,39 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 
+import java.math.BigInteger;
+import java.util.List;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
+import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
+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.PortNumber;
+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.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider {
+
+    static final Logger logger = LoggerFactory.getLogger(IngressAclService.class);
 
-public class IngressAclService extends AbstractServiceInstance {
     public IngressAclService() {
         super(Service.INGRESS_ACL);
     }
@@ -22,7 +51,419 @@ public class IngressAclService extends AbstractServiceInstance {
     }
 
     @Override
-    public boolean isBridgeInPipeline (String nodeId) {
+    public boolean isBridgeInPipeline(String nodeId) {
         return true;
     }
-}
\ No newline at end of file
+
+    @Override
+    public void programPortSecurityACL(Node node, Long dpid, String segmentationId, String attachedMac,
+            long localPort, NeutronSecurityGroup securityGroup) {
+
+        logger.trace("programLocalBridgeRulesWithSec neutronSecurityGroup: {} ", securityGroup);
+        List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
+        /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
+        for (NeutronSecurityRule portSecurityRule : portSecurityList) {
+            /**
+             * Neutron Port Security ACL "ingress" and "IPv4"
+             *
+             * Check that the base conditions for flow based Port Security are true:
+             * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
+             * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
+             * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
+             *
+             */
+            if (portSecurityRule.getSecurityRuleEthertype().equalsIgnoreCase("IPv4") &&
+                    portSecurityRule.getSecurityRuleDirection().equalsIgnoreCase("ingress")) {
+                logger.debug("ACL Rule matching IPv4 and ingress is: {} ", portSecurityRule);
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                                !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                                        .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug("Rule #1 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                            Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
+                            true);
+                    ingressACLTcpPortWithPrefix(dpid, segmentationId,
+                            attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                                !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                                        .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug("Rule #2 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
+                            true);
+                    ingressACLTcpPortWithPrefix(dpid, segmentationId,
+                            attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug("Rule #3 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PREFIX_MATCH_PRIORITY_DROP,
+                            true);
+                    ingressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (False), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
+                                !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                                        .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug("Rule #4 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PREFIX_MATCH_PRIORITY_DROP, true);
+                    ingressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PREFIX_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (False)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug("Rule #5 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PORT_MATCH_PRIORITY_DROP,
+                            true);
+                    ingressACLTcpSyn(dpid, segmentationId,
+                            attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
+                            Constants.PREFIX_PORT_MATCH_PRIORITY_DROP);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (False)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
+                    logger.debug("Rule #6 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
+                                             Constants.PROTO_PORT_MATCH_PRIORITY_DROP, true);
+                    ingressACLTcpSyn(dpid, segmentationId, attachedMac, true,
+                            portSecurityRule.getSecurityRulePortMin(), Constants.PROTO_PORT_MATCH_PRIORITY);
+                    continue;
+                }
+                /**
+                 * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (False or 0.0.0.0/0)
+                 */
+                if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
+                        String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
+                        ((String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) ||
+                                String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
+                                        .equalsIgnoreCase("0.0.0.0/0"))) {
+                    logger.debug("Rule #7 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
+                            portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
+                            portSecurityRule.getSecurityRulePortMax(),
+                            portSecurityRule.getSecurityRuleRemoteIpPrefix());
+                    // No need to drop until UDP/ICMP are implemented
+                    // ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, PROTO_MATCH_PRIORITY_DROP, true);
+                    handleIngressAllowProto(dpid, segmentationId, attachedMac, true,
+                            portSecurityRule.getSecurityRuleProtocol(), Constants.PROTO_MATCH_PRIORITY);
+                    continue;
+                }
+                logger.debug("Ingress ACL Match combination not found for rule: {}", portSecurityRule);
+            }
+        }
+    }
+
+    public void ingressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
+            Integer securityRulePortMin, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        PortNumber tcpPort = new PortNumber(securityRulePortMin);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createDmacTcpSynMatch(matchBuilder, attachedMac, tcpPort,
+                                                              Constants.TCP_SYN, segmentationId).build());
+
+        logger.debug("ingressACLTcpSyn MatchBuilder contains:  {}", flowBuilder.getMatch());
+        String flowId = "UcastOut_ACL2" + segmentationId + "_" + attachedMac + securityRulePortMin;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions are: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void ingressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac,
+            boolean write, Integer securityRulePortMin, String securityRuleIpPrefix,
+            Integer protoPortPrefixMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        PortNumber tcpPort = new PortNumber(securityRulePortMin);
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = this.createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
+
+        flowBuilder.setMatch(MatchUtils
+                .createDmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
+                        tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix).build());
+
+        logger.debug(" MatchBuilder contains:  {}", flowBuilder.getMatch());
+        String flowId = "UcastOut2_" + segmentationId + "_" + attachedMac +
+                securityRulePortMin + securityRuleIpPrefix;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortPrefixMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            List<Instruction> instructionsList = Lists.newArrayList();
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void handleIngressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
+            String securityRuleProtcol, Integer protoMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils
+                .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null).build());
+        flowBuilder.setMatch(MatchUtils
+                .createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+
+        String flowId = "UcastOut_" + segmentationId + "_" +
+                attachedMac + "_AllowTCPSynPrefix_" + securityRuleProtcol;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(1));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+
+    public void ingressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
+            int priority, boolean write) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createDmacTcpPortWithFlagMatch(matchBuilder,
+                attachedMac, Constants.TCP_SYN, segmentationId).build());
+
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "PortSec_TCP_Syn_Default_Drop_" + attachedMac;
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(priority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = Lists.newArrayList();
+
+            // Set the Output Port/Iface
+            InstructionUtils.createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    public void ingressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
+            boolean write, String securityRuleIpPrefix, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId))
+                .build());
+        if (securityRuleIpPrefix != null) {
+            flowBuilder.setMatch(MatchUtils
+                    .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix)
+                    .build());
+        } else {
+            flowBuilder.setMatch(MatchUtils
+                    .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null)
+                    .build());
+        }
+
+        logger.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "IngressProto_ACL_" + segmentationId + "_" +
+                attachedMac + "_Permit_" + securityRuleIpPrefix;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(false);
+        flowBuilder.setPriority(protoPortMatchPriority);
+        flowBuilder.setBarrier(true);
+        flowBuilder.setTableId(this.getTable());
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+            List<Instruction> instructionsList = Lists.newArrayList();
+
+            ib = this.getMutablePipelineInstructionBuilder();
+            ib.setOrder(1);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+}
index 907aeaa32026f7752f36ef5b49a1aeb1a9110d4e..5e38d1507743d191ebb373d13c45a803ea535b5a 100644 (file)
@@ -42,6 +42,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.OutboundNatProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.api.RoutingProvider;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.VlanConfigurationCache;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.BridgeConfigurationManagerImpl;
@@ -50,6 +51,7 @@ import org.opendaylight.ovsdb.openstack.netvirt.impl.EventDispatcherImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.OpenstackRouter;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.ProviderNetworkManagerImpl;
+import org.opendaylight.ovsdb.openstack.netvirt.impl.SecurityServicesImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.TenantNetworkManagerImpl;
 import org.opendaylight.ovsdb.openstack.netvirt.impl.VlanConfigurationCacheImpl;
 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
@@ -108,7 +110,8 @@ public class Activator extends ComponentActivatorAbstractBase {
                         LBaaSHandler.class,
                         LBaaSPoolMemberHandler.class,
                         NeutronL3Adapter.class,
-                        OpenstackRouter.class};
+                        OpenstackRouter.class,
+                        SecurityServicesImpl.class};
         return res;
     }
 
@@ -275,11 +278,16 @@ public class Activator extends ComponentActivatorAbstractBase {
             Properties portSecurityHandlerProperties = new Properties();
             portSecurityHandlerProperties.put(Constants.EVENT_HANDLER_TYPE_PROPERTY,
                                               AbstractEvent.HandlerType.NEUTRON_PORT_SECURITY);
-            c.setInterface(new String[] {INeutronSecurityRuleAware.class.getName(),
-                                         INeutronSecurityGroupAware.class.getName(),
-                                         AbstractHandler.class.getName()},
+            c.setInterface(new String[]{INeutronSecurityRuleAware.class.getName(),
+                                        INeutronSecurityGroupAware.class.getName(),
+                            AbstractHandler.class.getName()},
                            portSecurityHandlerProperties);
             c.add(createServiceDependency().setService(EventDispatcher.class).setRequired(true));
+            c.add(createServiceDependency().setService(SecurityServicesManager.class).setRequired(true));
+        }
+
+        if (imp.equals(SecurityServicesImpl.class)) {
+            c.setInterface(new String[] {SecurityServicesManager.class.getName()}, null);
         }
 
         if (imp.equals(FWaasHandler.class)) {
index 537c7c7382a39071d594b3ca2a568d140abc447e..acf7a9b496ea226320dd2d6a5aaf354b57171845 100644 (file)
@@ -73,4 +73,27 @@ public final class Constants {
      * Ethertypes
      */
     public static final long ARP_ETHERTYPE = 0x0806L;
+
+
+    /*
+     * ACL
+     */
+    public static final Integer PROTO_MATCH_PRIORITY_DROP = 36006;
+    public static final Integer PROTO_PORT_MATCH_PRIORITY_DROP = 36005;
+    public static final Integer PREFIX_MATCH_PRIORITY_DROP = 36004;
+    public static final Integer PROTO_PREFIX_MATCH_PRIORITY_DROP = 36003;
+    public static final Integer PREFIX_PORT_MATCH_PRIORITY_DROP = 36002;
+    public static final Integer PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP = 36001;
+
+    public static final Integer PROTO_MATCH_PRIORITY = 61010;
+    public static final Integer PREFIX_MATCH_PRIORITY = 61009;
+    public static final Integer PROTO_PREFIX_MATCH_PRIORITY = 61008;
+    public static final Integer PROTO_PORT_MATCH_PRIORITY = 61007;
+    public static final Integer PROTO_PORT_PREFIX_MATCH_PRIORITY = 61007;
+
+    public static final int TCP_SYN = 0x002;
+    public static final short INGRESS_ACL = 40; // Flows Destined to the VM Port go here
+    public static final short OUTBOUND_SNAT = 110; // Ingress ACL table drains traffic to this table
+
+    private static Long groupId = 1L;
 }
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EgressAclProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/EgressAclProvider.java
new file mode 100644 (file)
index 0000000..fb037ee
--- /dev/null
@@ -0,0 +1,23 @@
+package org.opendaylight.ovsdb.openstack.netvirt.api;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ *  This interface allows egress Port Security flows to be written to devices
+ */
+public interface EgressAclProvider {
+
+    /**
+     * Program port security ACL.
+     *
+     * @param node the node
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param securityGroup the security group
+     */
+    public void programPortSecurityACL(Node node, Long dpid, String segmentationId, String attachedMac,
+                                       long localPort, NeutronSecurityGroup securityGroup);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java
new file mode 100644 (file)
index 0000000..1589294
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.ovsdb.openstack.netvirt.api;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ *  This interface allows ingress Port Security flows to be written to devices
+ */
+public interface IngressAclProvider {
+
+    /**
+     * Program port security ACL.
+     *
+     * @param node the node
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param securityGroup the security group
+     */
+    public void programPortSecurityACL(Node node, Long dpid, String segmentationId, String attachedMac,
+            long localPort, NeutronSecurityGroup securityGroup);
+}
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java
new file mode 100644 (file)
index 0000000..7904dbf
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.ovsdb.openstack.netvirt.api;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+
+/**
+ * Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge
+ * This class manages the provisioning of these VLANs
+ */
+public interface SecurityServicesManager {
+    /**
+     * Is port security ready.
+     *
+     * @param intf the intf
+     * @return the boolean
+     */
+    public boolean isPortSecurityReady(Interface intf);
+    /**
+     * Gets security group in port.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public NeutronSecurityGroup getSecurityGroupInPort(Interface intf);
+
+}
\ No newline at end of file
diff --git a/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java b/openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java
new file mode 100644 (file)
index 0000000..cf912dc
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.ovsdb.openstack.netvirt.impl;
+
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
+import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
+
+import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+public class SecurityServicesImpl implements SecurityServicesManager {
+
+    static final Logger logger = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
+
+    public SecurityServicesImpl() {
+    }
+
+    /**
+     * Is security group ready.
+     *
+     * @param intf the intf
+     * @return the boolean
+     */
+    public boolean isPortSecurityReady(Interface intf) {
+        logger.trace("getTenantNetworkForInterface for {}", intf);
+        if (intf == null) return false;
+        Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
+        logger.trace("externalIds {}", externalIds);
+        if (externalIds == null) return false;
+        String neutronPortId = externalIds.get(Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) return false;
+        INeutronPortCRUD neutronPortService = (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class,
+                this);
+        NeutronPort neutronPort = neutronPortService.getPort(neutronPortId);
+        String deviceOwner = neutronPort.getDeviceOwner();
+        if (!deviceOwner.contains("compute")) {
+            logger.debug("Port {} is not a compute host, it is a: {}", neutronPortId, deviceOwner);
+        }
+        logger.debug("isPortSecurityReady() is a {} ", deviceOwner);
+        List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
+        if (securityGroups.isEmpty()) {
+            logger.debug("Check for device: {} does not contain a Security Group for port: {}", deviceOwner,
+                    neutronPortId);
+            return false;
+        }
+        try {
+            String vmPort = externalIds.get("attached-mac");
+        } catch(Exception e) {
+            logger.debug("Error VMID did *NOT* work");
+        }
+        logger.debug("Security Group Check {} DOES contain a Neutron Security Group", neutronPortId);
+        return true;
+    }
+
+    /**
+     * Gets security group in port.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public NeutronSecurityGroup getSecurityGroupInPort(Interface intf) {
+        logger.trace("getTenantNetworkForInterface for {}", intf);
+        if (intf == null) return null;
+        Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
+        logger.trace("externalIds {}", externalIds);
+        if (externalIds == null) return null;
+        String neutronPortId = externalIds.get(Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) return null;
+        INeutronPortCRUD neutronPortService = (INeutronPortCRUD)
+                ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+        NeutronPort neutronPort = neutronPortService.getPort(neutronPortId);
+        List<NeutronSecurityGroup> neutronSecurityGroups = neutronPort.getSecurityGroups();
+        NeutronSecurityGroup neutronSecurityGroup = (NeutronSecurityGroup) neutronSecurityGroups.toArray()[0];
+        return neutronSecurityGroup;
+    }
+}
index 73632486b3d9abfa7af4158c06916101d5958ae5..de1463805419619860050bbc3faabec5d6162f97 100644 (file)
@@ -286,35 +286,8 @@ public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigServ
     @Deprecated
     public Status updateRow (Node node, String tableName, String parentUUID, String rowUUID, Row row) {
         String databaseName = OvsVswitchdSchemaConstants.DATABASE_NAME;
-        Connection connection = connectionService.getConnection(node);
-        OvsdbClient client = connection.getClient();
-
-        logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
-                      client.getConnectionInfo(), databaseName, tableName, rowUUID, row.toString());
-        try{
-            DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
-            TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
-            TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
-            ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
-            transactionBuilder.add(op.update(tableSchema, row)
-                                     .where(_uuid.opEqual(new UUID(rowUUID)))
-                                     .build());
-
-            ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
-            List<OperationResult> operationResults = results.get();
-            if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
-                return new StatusWithUuid(StatusCode.INTERNALERROR);
-            }
-            for (OperationResult result : operationResults) {
-                if (result.getError() != null) {
-                    return new StatusWithUuid(StatusCode.BADREQUEST, result.getError());
-                }
-            }
-            return new StatusWithUuid(StatusCode.SUCCESS);
-        } catch(Exception e){
-            logger.error("Error in updateRow(): ",e);
-        }
-        return new Status(StatusCode.INTERNALERROR);
+        Row<GenericTableSchema> updatedRow = this.updateRow(node, databaseName, tableName, new UUID(rowUUID), row, true);
+        return new StatusWithUuid(StatusCode.SUCCESS);
     }
 
     private void processDeleteTransaction(OvsdbClient client, String databaseName, String childTable,
@@ -396,9 +369,7 @@ public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigServ
     @Override
     @Deprecated
     public List<String> getTables(Node node) {
-        ConcurrentMap<String, ConcurrentMap<String, Row>> cache  = ovsdbInventoryService.getCache(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
-        if (cache == null) return null;
-        return new ArrayList<String>(cache.keySet());
+        return this.getTables(node, OvsVswitchdSchemaConstants.DATABASE_NAME);
     }
 
     private List<InetAddress> getControllerIPAddresses(Connection connection) {
@@ -1502,43 +1473,117 @@ public class ConfigurationServiceImpl implements IPluginInBridgeDomainConfigServ
     public Row<GenericTableSchema> updateRow(Node node, String databaseName,
             String tableName, UUID rowUuid, Row<GenericTableSchema> row,
             boolean overwrite) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        Connection connection = connectionService.getConnection(node);
+        OvsdbClient client = connection.getClient();
+
+        logger.debug("updateRow : Connection : {} databaseName : {} tableName : {} rowUUID : {} row : {}",
+                      client.getConnectionInfo(), databaseName, tableName, rowUuid, row.toString());
+        try{
+            DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
+            TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
+            TableSchema<GenericTableSchema> tableSchema = dbSchema.table(tableName, GenericTableSchema.class);
+            ColumnSchema<GenericTableSchema, UUID> _uuid = tableSchema.column("_uuid", UUID.class);
+            transactionBuilder.add(op.update(tableSchema, row)
+                                     .where(_uuid.opEqual(rowUuid))
+                                     .build());
+
+            ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
+            List<OperationResult> operationResults = results.get();
+            for (OperationResult result : operationResults) {
+                if (result.getError() != null) {
+                    throw new OvsdbPluginException("Error updating row : "+ result.getError());
+                }
+            }
+            if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
+                throw new OvsdbPluginException("Failed to update row. Please check OVS logs for more info.");
+            }
+
+            return this.getRow(node, databaseName, tableName, rowUuid);
+        } catch(Exception e){
+            throw new OvsdbPluginException("Error updating row due to an exception "+ e.getMessage());
+        }
     }
 
     @Override
     public void deleteRow(Node node, String databaseName, String tableName, String parentTable, UUID parentRowUuid,
             String parentColumn, UUID rowUuid) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        Connection connection = connectionService.getConnection(node);
+        OvsdbClient client = connection.getClient();
+
+        if (parentTable == null && parentRowUuid != null) {
+            parentTable = this.getTableNameForRowUuid(node, databaseName, parentRowUuid);
+        }
+
+        if (parentColumn == null && parentTable != null) {
+            DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
+            TableSchema<GenericTableSchema> parentTableSchema = dbSchema.table(parentTable, GenericTableSchema.class);
+            parentColumn = this.getReferencingColumn(parentTableSchema, tableName);
+        }
+
+        logger.debug("deleteRow : Connection : {} databaseName : {} tableName : {} Uuid : {} ParentTable : {} ParentColumn : {}",
+                client.getConnectionInfo(), databaseName, tableName, rowUuid, parentTable, parentColumn);
+
+        DatabaseSchema dbSchema = client.getDatabaseSchema(databaseName);
+        TransactionBuilder transactionBuilder = client.transactBuilder(dbSchema);
+        this.processDeleteTransaction(client, databaseName, tableName,
+                                      parentTable, parentColumn, rowUuid.toString(), transactionBuilder);
+
+        ListenableFuture<List<OperationResult>> results = transactionBuilder.execute();
+        List<OperationResult> operationResults;
+        try {
+            operationResults = results.get();
+            if (operationResults.isEmpty() || (transactionBuilder.getOperations().size() != operationResults.size())) {
+                throw new OvsdbPluginException("Delete Operation Failed");
+            }
+            for (OperationResult result : operationResults) {
+                if (result.getError() != null) {
+                    throw new OvsdbPluginException("Delete Operation Failed with Error : "+result.getError().toString());
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
     }
 
     @Override
-    public void deleteRow(Node node, String databaseName, String tableName,
-            UUID rowUuid) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+    public void deleteRow(Node node, String databaseName, String tableName, UUID rowUuid) throws OvsdbPluginException {
+        this.deleteRow(node, databaseName, tableName, null, null, null, rowUuid);
     }
 
     @Override
     public Row<GenericTableSchema> getRow(Node node, String databaseName,
             String tableName, UUID uuid) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        ConcurrentMap<UUID, Row<GenericTableSchema>> rows = this.getRows(node, databaseName, tableName);
+        if (rows != null) {
+            return rows.get(uuid);
+        }
+        return null;
     }
 
     @Override
     public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
             String databaseName, String tableName) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        ConcurrentMap<String, Row> ovsTable = ovsdbInventoryService.getTableCache(node, databaseName, tableName);
+        if (ovsTable == null) return null;
+        ConcurrentMap<UUID, Row<GenericTableSchema>> tableDB = Maps.newConcurrentMap();
+        for (String uuidStr : ovsTable.keySet()) {
+            tableDB.put(new UUID(uuidStr), ovsTable.get(uuidStr));
+        }
+        return tableDB;
     }
 
     @Override
     public ConcurrentMap<UUID, Row<GenericTableSchema>> getRows(Node node,
             String databaseName, String tableName, String fiqlQuery)
             throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        return this.getRows(node, databaseName, tableName);
     }
 
     @Override
     public List<String> getTables(Node node, String databaseName) throws OvsdbPluginException {
-        throw new OvsdbPluginException("Not implemented Yet");
+        ConcurrentMap<String, ConcurrentMap<String, Row>> cache  = ovsdbInventoryService.getCache(node, databaseName);
+        if (cache == null) return null;
+        return new ArrayList<String>(cache.keySet());
     }
-}
-
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c2a1b8b9d7144a601dbcef26638cc116671da78c..f2bed7952b9b42d95c7e7d853cd90cbe6b840b69 100755 (executable)
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,7 @@
     <!-- Karaf Distribution -->
     <module>features/ovsdb</module>
     <module>features/of-nxm-extensions</module>
+    <module>features/ovs-sfc</module>
     <!-- OVSDB Distribution -->
     <module>distribution/opendaylight</module>
   </modules>
index 22f78f14c211e152dbbf9dbf7ed19e4c1f11d68f..8ad2aace18e118be5fc72fb67b941e67ae610db4 100644 (file)
@@ -73,6 +73,12 @@ import com.google.common.collect.Lists;
 
 public class MatchUtils {
     private static final Logger logger = LoggerFactory.getLogger(MatchUtils.class);
+    public static final short ICMP_SHORT = 1;
+    public static final short TCP_SHORT = 6;
+    public static final short UDP_SHORT = 17;
+    public static final String TCP = "tcp";
+    public static final String UDP = "udp";
+    private static final int TCP_SYN = 0x0002;
 
     /**
      * Create Ingress Port Match dpidLong, inPort
@@ -365,6 +371,473 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    /**
+     * Create  TCP Port Match
+     *
+     * @param matchBuilder @param matchbuilder MatchBuilder Object without a match yet
+     * @param tcpport      Integer representing a source TCP port
+     * @return matchBuilder Map MatchBuilder Object with a match
+     */
+    public static MatchBuilder createIpProtocolMatch(MatchBuilder matchBuilder, short ipProtocol) {
+
+        EthernetMatchBuilder ethType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethType.build());
+
+        IpMatchBuilder ipMmatch = new IpMatchBuilder();
+        if (ipProtocol == TCP_SHORT) {
+            ipMmatch.setIpProtocol(TCP_SHORT);
+        }
+        else if (ipProtocol == UDP_SHORT) {
+            ipMmatch.setIpProtocol(UDP_SHORT);
+        }
+        else if (ipProtocol == ICMP_SHORT) {
+            ipMmatch.setIpProtocol(ICMP_SHORT);
+        }
+        matchBuilder.setIpMatch(ipMmatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create tcp syn with proto match.
+     *
+     * @param matchBuilder the match builder
+     * @return matchBuilder match builder
+     */
+    public static MatchBuilder createTcpSynWithProtoMatch(MatchBuilder matchBuilder) {
+
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create tcp proto syn match.
+     *
+     * @param matchBuilder the match builder
+     * @return matchBuilder match builder
+     */
+    public static MatchBuilder createTcpProtoSynMatch(MatchBuilder matchBuilder) {
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp port with flag match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return match containing TCP_Flag (), IP Protocol (TCP), TCP_Flag (SYN)
+     */
+    public static MatchBuilder createDmacTcpPortWithFlagMatch(MatchBuilder matchBuilder,
+            String attachedMac, Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return the match builder
+     */
+    public static MatchBuilder createDmacTcpSynMatch(MatchBuilder matchBuilder,
+            String attachedMac, PortNumber tcpPort, Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac tcp syn dst ip prefix tcp port.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param segmentationId the segmentation id
+     * @param dstIp the dst ip
+     * @return the match builder
+     */
+    public static MatchBuilder createDmacTcpSynDstIpPrefixTcpPort(MatchBuilder matchBuilder,
+            MacAddress attachedMac, PortNumber tcpPort,  Integer tcpFlag, String segmentationId,
+            Ipv4Prefix dstIp) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Destination(dstIp);
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(segmentationId));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create dmac ip tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param dMacAddr the d mac addr
+     * @param mask the mask
+     * @param ipPrefix the ip prefix
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createDmacIpTcpSynMatch(MatchBuilder matchBuilder,
+            MacAddress dMacAddr, MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetDestinationBuilder ethDestBuilder = new EthernetDestinationBuilder();
+        ethDestBuilder.setAddress(new MacAddress(dMacAddr));
+        if (mask != null) {
+            ethDestBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Destination(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp syn dst ip prefix tcp port.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param segmentationId the segmentation id
+     * @param dstIp the dst ip
+     * @return the match builder
+     */
+    public static MatchBuilder createSmacTcpSynDstIpPrefixTcpPort(MatchBuilder matchBuilder, MacAddress attachedMac,
+            PortNumber tcpPort, Integer tcpFlag, String segmentationId, Ipv4Prefix dstIp) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+        ipv4match.setIpv4Destination(dstIp);
+        matchBuilder.setLayer3Match(ipv4match.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(segmentationId));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp port with flag match.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return matchBuilder
+     */
+    public static MatchBuilder createSmacTcpPortWithFlagMatch(MatchBuilder matchBuilder, String attachedMac,
+            Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac ip tcp syn match.
+     *
+     * @param matchBuilder the match builder
+     * @param dMacAddr the d mac addr
+     * @param mask the mask
+     * @param ipPrefix the ip prefix
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createSmacIpTcpSynMatch(MatchBuilder matchBuilder, MacAddress dMacAddr,
+            MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(new MacAddress(dMacAddr));
+        if (mask != null) {
+            ethSrcBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Destination(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * Create smac tcp syn.
+     *
+     * @param matchBuilder the match builder
+     * @param attachedMac the attached mac
+     * @param tcpPort the tcp port
+     * @param tcpFlag the tcp flag
+     * @param tunnelID the tunnel iD
+     * @return the match builder
+     */
+    public static MatchBuilder createSmacTcpSyn(MatchBuilder matchBuilder,
+            String attachedMac, PortNumber tcpPort, Integer tcpFlag, String tunnelID) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+
+        EthernetSourceBuilder ethSrcBuilder = new EthernetSourceBuilder();
+        ethSrcBuilder.setAddress(new MacAddress(attachedMac));
+        ethernetMatch.setEthernetSource(ethSrcBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol((short) 6);
+        matchBuilder.setIpMatch(ipMatch.build());
+
+        // TCP Port Match
+        PortNumber dstPort = new PortNumber(tcpPort);
+        TcpMatchBuilder tcpMatch = new TcpMatchBuilder();
+        tcpMatch.setTcpDestinationPort(dstPort);
+        matchBuilder.setLayer4Match(tcpMatch.build());
+
+
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(tcpFlag);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        TunnelBuilder tunnelBuilder = new TunnelBuilder();
+        tunnelBuilder.setTunnelId(new BigInteger(tunnelID));
+        matchBuilder.setTunnel(tunnelBuilder.build());
+
+        return matchBuilder;
+    }
+
+    /**
+     * @return MatchBuilder containing the metadata match values
+     */
+    public static MatchBuilder createMacSrcIpTcpSynMatch(MatchBuilder matchBuilder,
+            MacAddress dMacAddr,  MacAddress mask, Ipv4Prefix ipPrefix) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetDestinationBuilder ethDestinationBuilder = new EthernetDestinationBuilder();
+        ethDestinationBuilder.setAddress(new MacAddress(dMacAddr));
+        if (mask != null) {
+            ethDestinationBuilder.setMask(mask);
+        }
+        ethernetMatch.setEthernetDestination(ethDestinationBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+        // Ethertype match
+        EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetType.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetType.build());
+        if (ipPrefix != null) {
+            Ipv4MatchBuilder ipv4match = new Ipv4MatchBuilder();
+            ipv4match.setIpv4Source(ipPrefix);
+            matchBuilder.setLayer3Match(ipv4match.build());
+        }
+        // TCP Protocol Match
+        IpMatchBuilder ipMatch = new IpMatchBuilder(); // ipv4 version
+        ipMatch.setIpProtocol(TCP_SHORT);
+        matchBuilder.setIpMatch(ipMatch.build());
+        // TCP Flag Match
+        TcpFlagMatchBuilder tcpFlagMatch = new TcpFlagMatchBuilder();
+        tcpFlagMatch.setTcpFlag(TCP_SYN);
+        matchBuilder.setTcpFlagMatch(tcpFlagMatch.build());
+
+        return matchBuilder;
+    }
+
     public static class RegMatch {
         final Class<? extends NxmNxReg> reg;
         final Long value;