[ONOS-3953] Implements Security Group of Openstack

Change-Id: I30766097a2894a26e46a7a399176d99e95af6abf
diff --git a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackSecurityGroupRule.java b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackSecurityGroupRule.java
index 42a4a44..c2fe875 100644
--- a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackSecurityGroupRule.java
+++ b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackSecurityGroupRule.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstackinterface;
 
+import org.onlab.packet.IpPrefix;
+
 import java.util.Objects;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -24,25 +26,34 @@
  */
 public final class OpenstackSecurityGroupRule {
 
-    private final String direction;
+    private final Direction direction;
     private final String ethertype;
     private final String id;
-    private final String portRangeMax;
-    private final String portRangeMin;
+    private final int portRangeMax;
+    private final int portRangeMin;
     private final String protocol;
     private final String remoteGroupId;
-    private final String remoteIpPrefix;
+    private final IpPrefix remoteIpPrefix;
     private final String secuityGroupId;
     private final String tenantId;
 
-    private OpenstackSecurityGroupRule(String direction,
+    /**
+     * Direction of the Security Group.
+     *
+     */
+    public enum Direction {
+        INGRESS,
+        EGRESS
+    }
+
+    private OpenstackSecurityGroupRule(Direction direction,
                                        String ethertype,
                                        String id,
-                                       String portRangeMax,
-                                       String portRangeMin,
+                                       int portRangeMax,
+                                       int portRangeMin,
                                        String protocol,
                                        String remoteGroupId,
-                                       String remoteIpPrefix,
+                                       IpPrefix remoteIpPrefix,
                                        String securityGroupId,
                                        String tenantId) {
         this.direction = direction;
@@ -57,6 +68,105 @@
         this.tenantId = tenantId;
     }
 
+    /**
+     * Returns the builder object for the OpenstackSecurityGroupRule.
+     *
+     * @return OpenstackSecurityGroupRule builder object
+     */
+    public static OpenstackSecurityGroupRule.Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Returns the direction.
+     *
+     * @return direction
+     */
+    public Direction direction() {
+        return direction;
+    }
+
+    /**
+     * Returns the Ethernet type.
+     *
+     * @return Ethernet type
+     */
+    public String ethertype() {
+        return ethertype;
+    }
+
+    /**
+     * Returns the Security Group ID.
+     *
+     * @return Security Group ID
+     */
+    public String id() {
+        return id;
+    }
+
+    /**
+     * Returns the max of the port range.
+     *
+     * @return max of the port range
+     */
+    public int portRangeMax() {
+        return portRangeMax;
+    }
+
+    /**
+     * Returns the min of the port range.
+     *
+     * @return min of the port range
+     */
+    public int portRangeMin() {
+        return portRangeMin;
+    }
+
+    /**
+     * Returns the IP protocol.
+     *
+     * @return IP protocol
+     */
+    public String protocol() {
+        return protocol;
+    }
+
+    /**
+     * Returns the remote group ID.
+     *
+     * @return remote group ID
+     */
+    public String remoteGroupId() {
+        return remoteGroupId;
+    }
+
+    /**
+     * Returns the remote IP address.
+     *
+     * @return remote IP address
+     */
+    public IpPrefix remoteIpPrefix() {
+        return this.remoteIpPrefix;
+    }
+
+    /**
+     * Returns the Security Group ID.
+     *
+     * @return security group ID
+     */
+    public String secuityGroupId() {
+        return secuityGroupId;
+    }
+
+    /**
+     * Returns the tenant ID.
+     *
+     * @return tenant ID
+     */
+    public String tenantId() {
+        return tenantId;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder(" [")
@@ -84,8 +194,8 @@
             return this.direction.equals(that.direction) &&
                     this.ethertype.equals(that.direction) &&
                     this.id.equals(that.id) &&
-                    this.portRangeMax.equals(that.portRangeMax) &&
-                    this.portRangeMin.equals(that.portRangeMin) &&
+                    this.portRangeMax == that.portRangeMax &&
+                    this.portRangeMin == that.portRangeMin &&
                     this.protocol.equals(that.protocol) &&
                     this.remoteGroupId.equals(that.remoteGroupId) &&
                     this.secuityGroupId.equals(that.secuityGroupId) &&
@@ -235,8 +345,16 @@
          * @return OpenstackSecurityGroupRule object
          */
         public OpenstackSecurityGroupRule build() {
-            return new OpenstackSecurityGroupRule(direction, etherType, id, portRangeMax,
-                    portRangeMin, protocol, remoteGroupId, remoteIpPrefix, secuityGroupId, tenantId);
+
+            int portRangeMinInt = (portRangeMin == null || portRangeMin.equals("null")) ?
+                    -1 : Integer.parseInt(portRangeMax);
+            int portRangeMaxInt = (portRangeMax == null || portRangeMax.equals("null")) ?
+                    -1 : Integer.parseInt(portRangeMax);
+            IpPrefix ipPrefix = (remoteIpPrefix == null || remoteIpPrefix.equals("null")) ?
+                    null : IpPrefix.valueOf(remoteIpPrefix);
+
+            return new OpenstackSecurityGroupRule(Direction.valueOf(direction.toUpperCase()), etherType, id,
+                    portRangeMaxInt, portRangeMinInt, protocol, remoteGroupId, ipPrefix, secuityGroupId, tenantId);
         }
     }
 }
diff --git a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackSecurityGroupCodec.java b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackSecurityGroupCodec.java
index b2b0105..6b1fb8f 100644
--- a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackSecurityGroupCodec.java
+++ b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/web/OpenstackSecurityGroupCodec.java
@@ -48,7 +48,7 @@
     private static final String REMOTE_GROUP_ID = "remote_group_id";
     private static final String REMOTE_IP_PREFIX = "remote_ip_prefix";
     private static final String SECURITY_GROUP_ID = "security_group_id";
-    private static final String TENAN_ID = "tenant_id";
+    private static final String TENANT_ID = "tenant_id";
 
     @Override
     public OpenstackSecurityGroup decode(ObjectNode json, CodecContext context) {
@@ -75,12 +75,12 @@
                         .remoteGroupId(ruleInfo.path(REMOTE_GROUP_ID).asText())
                         .remoteIpPrefix(ruleInfo.path(REMOTE_IP_PREFIX).asText())
                         .securityGroupId(ruleInfo.path(SECURITY_GROUP_ID).asText())
-                        .tenantId(ruleInfo.path(TENAN_ID).asText())
+                        .tenantId(ruleInfo.path(TENANT_ID).asText())
                         .build();
 
             rules.add(openstackSecurityGroupRule);
         }
-        String tenantId = securityGroupNode.path(TENAN_ID).asText();
+        String tenantId = securityGroupNode.path(TENANT_ID).asText();
 
         OpenstackSecurityGroup openstackSecurityGroup = OpenstackSecurityGroup.builder()
                 .description(description)
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
index 0099ea9..0ab8681 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackPortInfo.java
@@ -18,6 +18,10 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
+
+import java.util.Collection;
+import java.util.Collections;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -29,70 +33,174 @@
     private final DeviceId deviceId;
     private final long vni;
     private final Ip4Address gatewayIP;
+    private final Collection<String> securityGroups;
 
-    public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni, Ip4Address gatewayIP) {
+    /**
+     * Returns OpenstackPortInfo reference.
+     *
+     * @param hostIp host IP address
+     * @param hostMac host MAC address
+     * @param deviceId device ID
+     * @param vni  tunnel ID
+     * @param gatewayIP gateway IP address
+     * @param securityGroups security group list
+     */
+    public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
+                             Ip4Address gatewayIP, Collection<String> securityGroups) {
         this.hostIp = hostIp;
         this.hostMac = hostMac;
         this.deviceId = deviceId;
         this.vni = vni;
         this.gatewayIP = gatewayIP;
+        this.securityGroups = securityGroups;
     }
 
+    /**
+     * Returns IP address of the port.
+     *
+     * @return IP address
+     */
     public Ip4Address ip() {
         return hostIp;
     }
 
+    /**
+     * Returns MAC address of the port.
+     *
+     * @return MAC address
+     */
     public MacAddress mac() {
         return hostMac;
     }
 
+    /**
+     * Returns device ID.
+     *
+     * @return device ID
+     */
     public DeviceId deviceId() {
         return deviceId;
     }
 
+    /**
+     * Returns tunnel ID.
+     *
+     * @return tunnel ID
+     */
     public long vni() {
         return vni;
     }
 
+    /**
+     * Returns gateway IP address.
+     *
+     * @return gateway IP address
+     */
     public Ip4Address gatewayIP() {
         return gatewayIP;
     }
 
+    /**
+     * Returns Security Group ID list.
+     *
+     * @return list of Security Group ID
+     */
+    public Collection<String> securityGroups() {
+        return Collections.unmodifiableCollection(securityGroups);
+    }
+
+    /**
+     * Returns the builder of the OpenstackPortInfo.
+     *
+     * @return OpenstackPortInfo builder reference
+     */
     public static OpenstackPortInfo.Builder builder() {
         return new Builder();
     }
 
+    /**
+     * Represents the OpenstackPortInfo Builder.
+     *
+     */
     public static final class Builder {
         private Ip4Address hostIp;
         private MacAddress hostMac;
         private DeviceId deviceId;
         private long vni;
         private Ip4Address gatewayIP;
+        private Collection<String> securityGroups;
 
+        /**
+         * Sets the IP address of the port.
+         *
+         * @param gatewayIP
+         * @return Builder reference
+         */
         public Builder setGatewayIP(Ip4Address gatewayIP) {
             this.gatewayIP = checkNotNull(gatewayIP, "gatewayIP cannot be null");
             return this;
         }
 
+        /**
+         * Sets the host IP address of the port.
+         *
+         * @param hostIp host IP address
+         * @return Builder reference
+         */
         public Builder setHostIp(Ip4Address hostIp) {
             this.hostIp = checkNotNull(hostIp, "hostIp cannot be null");
             return this;
         }
 
+        /**
+         * Sets the host MAC address of the port.
+         *
+         * @param hostMac host MAC address
+         * @return Builder reference
+         */
         public Builder setHostMac(MacAddress hostMac) {
             this.hostMac = checkNotNull(hostMac, "hostMac cannot be bull");
             return this;
         }
 
+        /**
+         * Sets the device ID.
+         *
+         * @param deviceId device ID
+         * @return Builder reference
+         */
         public Builder setDeviceId(DeviceId deviceId) {
             this.deviceId = checkNotNull(deviceId, "deviceId cannot be null");
             return this;
         }
 
+        /**
+         * Sets the tunnel ID.
+         *
+         * @param vni tunnel ID
+         * @return Builder reference
+         */
         public Builder setVni(long vni) {
             this.vni = checkNotNull(vni, "vni cannot be null");
             return this;
         }
+
+        /**
+         * Sets the security group ID list.
+         *
+         * @param securityGroups security group ID list
+         * @return Builder reference
+         */
+        public Builder setSecurityGroups(Collection<String> securityGroups) {
+            this.securityGroups = securityGroups;
+            return this;
+        }
+
+        /**
+         * Builds the OpenstackPortInfo reference.
+         *
+         * @return OpenstackPortInfo reference
+         */
         public OpenstackPortInfo build() {
             return new OpenstackPortInfo(this);
         }
@@ -104,5 +212,6 @@
         deviceId = builder.deviceId;
         vni = builder.vni;
         gatewayIP = builder.gatewayIP;
+        securityGroups = builder.securityGroups;
     }
 }
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
new file mode 100644
index 0000000..b16a6bf
--- /dev/null
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
@@ -0,0 +1,274 @@
+/*
+* Copyright 2016 Open Networking Laboratory
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.onosproject.openstacknetworking.switching;
+
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.openstackinterface.OpenstackInterfaceService;
+import org.onosproject.openstackinterface.OpenstackSecurityGroup;
+import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * Populates flows rules for Security Groups of VMs.
+ *
+ */
+public class OpenstackSecurityGroupRulePopulator {
+
+    private static Logger log = LoggerFactory
+            .getLogger(OpenstackSecurityGroupRulePopulator.class);
+
+    private OpenstackInterfaceService openstackService;
+    private FlowObjectiveService flowObjectiveService;
+
+    private ApplicationId appId;
+
+    private static final String PROTO_ICMP = "ICMP";
+    private static final String PROTO_TCP = "TCP";
+    private static final String PROTO_UDP = "UDP";
+
+    private static final String ETHTYPE_IPV4 = "IPV4";
+
+    private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
+
+    private static final int ACL_RULE_PRIORITY = 30000;
+
+    /**
+     * Constructor.
+     *
+     * @param appId
+     * @param openstackService
+     * @param flowObjectiveService
+     */
+    public OpenstackSecurityGroupRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
+                                               FlowObjectiveService flowObjectiveService) {
+        this.appId = appId;
+        this.openstackService = openstackService;
+        this.flowObjectiveService = flowObjectiveService;
+    }
+
+    /**
+     * Populates flow rules for security groups.
+     *
+     * @param id Device ID
+     * @param sgId Security Group ID
+     * @param vmIp VM IP address
+     * @param portInfoMap Port Info map
+     */
+    public void populateSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
+                                           Map<String, OpenstackPortInfo> portInfoMap) {
+        OpenstackSecurityGroup securityGroup = openstackService.getSecurityGroup(sgId);
+        if (securityGroup != null) {
+            securityGroup.rules().stream().forEach(sgRule -> {
+                if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
+                    openstackService.ports().stream()
+                        .filter(port -> port.securityGroups().contains(sgRule.remoteGroupId()))
+                        .flatMap(port -> port.fixedIps().values().stream())
+                        .forEach(remoteIp -> setSecurityGroupRule(id, sgRule,
+                                vmIp, IpPrefix.valueOf((IpAddress) remoteIp, 32)));
+                } else {
+                    setSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
+                }
+            });
+
+            openstackService.ports().stream().forEach(osPort ->
+                osPort.securityGroups().stream().forEach(remoteVmSgId -> {
+                    OpenstackSecurityGroup remoteVmSg = openstackService.getSecurityGroup(remoteVmSgId);
+                    remoteVmSg.rules().stream()
+                        .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
+                        .forEach(remoteVmSgRule -> {
+                            Ip4Address remoteVmIp =
+                                    (Ip4Address) osPort.fixedIps().values().stream().findAny().orElse(null);
+                            OpenstackPortInfo osPortInfo = portInfoMap.get(OpenstackSwitchingManager.PORTNAME_PREFIX_VM
+                                    + osPort.id().substring(0, 11));
+                            if (osPortInfo != null && remoteVmIp != null) {
+                                setSecurityGroupRule(osPortInfo.deviceId(), remoteVmSgRule, remoteVmIp,
+                                        IpPrefix.valueOf(vmIp, 32));
+                            }
+                        });
+                }));
+        }
+    }
+
+    /**
+     * Removes flow rules for security groups.
+     *
+     * @param id Device ID
+     * @param sgId Security Group ID to remove
+     * @param vmIp VM IP address
+     * @param portInfoMap port info map
+     * @param securityGroupMap security group info map
+     */
+    public void removeSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
+                                         Map<String, OpenstackPortInfo> portInfoMap,
+                                         Map<String, OpenstackSecurityGroup> securityGroupMap) {
+        OpenstackSecurityGroup securityGroup = securityGroupMap.get(sgId);
+        if (securityGroup != null) {
+            securityGroup.rules().stream().forEach(sgRule -> {
+                if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
+                    portInfoMap.values().stream()
+                            .filter(portInfo -> portInfo.securityGroups().contains(sgRule.remoteGroupId()))
+                            .map(OpenstackPortInfo::ip)
+                            .forEach(remoteIp -> {
+                                removeSecurityGroupRule(id, sgRule, vmIp, IpPrefix.valueOf(remoteIp, 32));
+                            });
+                } else {
+                    removeSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
+                }
+            });
+
+            portInfoMap.values().stream()
+                .forEach(portInfo -> portInfo.securityGroups()
+                    .forEach(remoteVmSgId -> {
+                        OpenstackSecurityGroup remoteVmSg = securityGroupMap.get(remoteVmSgId);
+                        remoteVmSg.rules().stream()
+                            .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
+                            .forEach(remoteVmSgRule -> removeSecurityGroupRule(portInfo.deviceId(),
+                                    remoteVmSgRule, portInfo.ip(), IpPrefix.valueOf(vmIp, 32)));
+                    }));
+        }
+    }
+
+    private void setSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
+                                      Ip4Address vmIp, IpPrefix remoteIp) {
+        ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
+        if (foBuilder != null) {
+            flowObjectiveService.forward(id, foBuilder.add());
+        }
+    }
+
+    private void removeSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
+                                      Ip4Address vmIp, IpPrefix remoteIp) {
+        ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
+        if (foBuilder != null) {
+            flowObjectiveService.forward(id, foBuilder.remove());
+        }
+    }
+
+    ForwardingObjective.Builder buildFlowObjective(DeviceId id, OpenstackSecurityGroupRule sgRule,
+                                           Ip4Address vmIp, IpPrefix remoteIp) {
+        if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
+            return null;
+        }
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
+
+        ForwardingObjective.Builder foBuilder = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withPriority(ACL_RULE_PRIORITY)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .fromApp(appId);
+
+        return foBuilder;
+    }
+
+    private void buildMatchs(TrafficSelector.Builder sBuilder, OpenstackSecurityGroupRule sgRule,
+                             Ip4Address vmIp, IpPrefix remoteIp) {
+        buildMatchEthType(sBuilder, sgRule.ethertype());
+        buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
+        buildMatchProto(sBuilder, sgRule.protocol());
+        buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(), sgRule.portRangeMax(), sgRule.portRangeMin());
+        buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
+    }
+
+    private void buildMatchDirection(TrafficSelector.Builder sBuilder,
+                                     OpenstackSecurityGroupRule.Direction direction, Ip4Address vmIp) {
+        if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+            sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
+        } else {
+            sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
+        }
+    }
+
+    private void buildMatchEthType(TrafficSelector.Builder sBuilder, String ethertype) {
+        // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4);
+        if (ethertype != null && ethertype != "null" &&
+                !ethertype.toUpperCase().equals(ETHTYPE_IPV4)) {
+            log.error("EthType {} is not supported yet in Security Group", ethertype);
+        }
+    }
+
+    private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix,
+                                                       OpenstackSecurityGroupRule.Direction direction) {
+        if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
+            if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                sBuilder.matchIPDst(remoteIpPrefix);
+            } else {
+                sBuilder.matchIPSrc(remoteIpPrefix);
+            }
+        }
+    }
+
+    private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
+        if (protocol != null) {
+            switch (protocol.toUpperCase()) {
+                case PROTO_ICMP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
+                    break;
+                case PROTO_TCP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
+                    break;
+                case PROTO_UDP:
+                    sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
+                    break;
+                default:
+            }
+        }
+    }
+
+    private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol,
+                                                   OpenstackSecurityGroupRule.Direction direction,
+                                                   int portMin, int portMax) {
+        if (portMin > 0 && portMax > 0 && portMin == portMax) {
+            if (protocol.toUpperCase().equals(PROTO_TCP)) {
+                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                    sBuilder.matchTcpDst(TpPort.tpPort(portMax));
+                } else {
+                    sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
+                }
+            } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
+                if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
+                    sBuilder.matchUdpDst(TpPort.tpPort(portMax));
+                } else {
+                    sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
+                }
+            }
+        }
+    }
+}
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
index 4e66d95..2c88b3a 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -104,7 +104,9 @@
     public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
 
     private ApplicationId appId;
-    private OpenstackArpHandler arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
+
+    private OpenstackArpHandler arpHandler;
+    private OpenstackSecurityGroupRulePopulator sgRulePopulator;
 
     private ExecutorService deviceEventExcutorService =
             Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
@@ -114,6 +116,7 @@
     private InternalHostListener internalHostListener = new InternalHostListener();
 
     private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
+    private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
 
     @Activate
     protected void activate() {
@@ -124,6 +127,9 @@
         deviceService.addListener(internalDeviceListener);
         hostService.addListener(internalHostListener);
 
+        arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
+        sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
+
         initializeFlowRules();
 
         log.info("Started");
@@ -148,13 +154,6 @@
                 registerDhcpInfo(openstackPort);
             }
         }
-
-        if (!openstackPort.securityGroups().isEmpty()) {
-            openstackPort.securityGroups().forEach(sgId -> {
-                OpenstackSecurityGroup sg = openstackService.getSecurityGroup(sgId);
-                log.debug("SecurityGroup : {}", sg.toString());
-            });
-        }
     }
 
     @Override
@@ -185,6 +184,22 @@
 
     @Override
     public void updatePort(OpenstackPort openstackPort) {
+        if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
+            String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
+            OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
+            if (osPortInfo != null) {
+                // Remove all security group rules based on the ones stored in security group map.
+                osPortInfo.securityGroups().stream().forEach(
+                        sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
+                                osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
+                // Add all security group rules based on the updated security group.
+                openstackPort.securityGroups().stream().forEach(
+                        sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
+                                osPortInfo.ip(), openstackPortInfoMap));
+                updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
+                        openstackService.subnets(), openstackPort);
+            }
+        }
     }
 
     @Override
@@ -205,26 +220,37 @@
     }
 
     private void processPortUpdated(Device device, Port port) {
-        if (!port.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL)) {
-            if (port.isEnabled() || port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER)) {
-                OpenstackSwitchingRulePopulator rulePopulator =
-                        new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                                deviceService, openstackService, driverService);
+        String portName = port.annotations().value(PORTNAME);
+        synchronized (openstackPortInfoMap) {
+            if (portName.startsWith(PORTNAME_PREFIX_VM)) {
+                if (port.isEnabled()) {
+                    OpenstackSwitchingRulePopulator rulePopulator =
+                            new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
+                                    deviceService, openstackService, driverService);
 
-                rulePopulator.populateSwitchingRules(device, port);
-                updatePortMap(device.id(), port, openstackService.networks(), openstackService.subnets(),
-                        rulePopulator.openstackPort(port));
+                    rulePopulator.populateSwitchingRules(device, port);
+                    OpenstackPort openstackPort = rulePopulator.openstackPort(port);
+                    Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
+                            .findAny().orElseGet(null);
+                    openstackPort.securityGroups().stream().forEach(
+                            sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
+                                    openstackPortInfoMap));
+                    updatePortMap(device.id(), port.annotations().value(PORTNAME),
+                            openstackService.networks(), openstackService.subnets(), openstackPort);
 
-                //In case portupdate event is driven by vm shutoff from openstack
-            } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value(PORTNAME))) {
-                log.debug("Flowrules according to the port {} were removed", port.number().toString());
-                OpenstackSwitchingRulePopulator rulePopulator =
-                        new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
-                                deviceService, openstackService, driverService);
-
-                rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
-                dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
-                openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
+                    //In case portupdate event is driven by vm shutoff from openstack
+                } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
+                    log.debug("Flowrules according to the port {} were removed", port.number().toString());
+                    OpenstackSwitchingRulePopulator rulePopulator =
+                            new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
+                                    deviceService, openstackService, driverService);
+                    rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
+                    openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
+                            sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
+                                    openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
+                    dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
+                    openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
+                }
             }
         }
     }
@@ -242,27 +268,33 @@
         Collection<OpenstackSubnet> subnets = openstackService.subnets();
 
         deviceService.getDevices().forEach(device -> {
-                    log.debug("device {} num of ports {} ", device.id(),
-                            deviceService.getPorts(device.id()).size());
-                    deviceService.getPorts(device.id()).stream()
-                            .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
-                                    port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
-                            .forEach(vmPort -> {
-                                        OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
-                                        if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
-                                            rulePopulator.populateSwitchingRules(device, vmPort);
-                                            updatePortMap(device.id(), vmPort, networks, subnets, osPort);
-                                            registerDhcpInfo(osPort);
-                                        } else {
-                                            log.warn("No openstackPort information for port {}", vmPort);
-                                        }
-                                    }
-                            );
+                log.debug("device {} num of ports {} ", device.id(),
+                        deviceService.getPorts(device.id()).size());
+                deviceService.getPorts(device.id()).stream()
+                        .filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
+                                port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
+                        .forEach(vmPort -> {
+                                OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
+                                if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
+                                    rulePopulator.populateSwitchingRules(device, vmPort);
+                                    Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
+                                            .findAny().orElseGet(null);
+                                    osPort.securityGroups().stream().forEach(
+                                            sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
+                                                    sgId, vmIp, openstackPortInfoMap));
+                                    updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
+                                            subnets, osPort);
+                                    registerDhcpInfo(osPort);
+                                } else {
+                                    log.warn("No openstackPort information for port {}", vmPort);
+                                }
+                            }
+                        );
                 }
         );
     }
 
-    private void updatePortMap(DeviceId deviceId, Port port, Collection<OpenstackNetwork> networks,
+    private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
                                Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
         long vni = Long.parseLong(networks.stream()
                 .filter(n -> n.id().equals(openstackPort.networkId()))
@@ -279,10 +311,17 @@
                 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
                 .setHostMac(openstackPort.macAddress())
                 .setVni(vni)
-                .setGatewayIP(gatewayIPAddress);
+                .setGatewayIP(gatewayIPAddress)
+                .setSecurityGroups(openstackPort.securityGroups());
 
-        openstackPortInfoMap.putIfAbsent(port.annotations().value(PORTNAME),
-                portBuilder.build());
+        openstackPortInfoMap.put(portName, portBuilder.build());
+
+        openstackPort.securityGroups().stream().forEach(sgId -> {
+            if (!securityGroupMap.containsKey(sgId)) {
+                securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
+            }
+        });
+
     }
 
     private void processHostRemoved(Host host) {
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
index 79ae523..9248d35 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingRulePopulator.java
@@ -58,7 +58,6 @@
     private static Logger log = LoggerFactory
             .getLogger(OpenstackSwitchingRulePopulator.class);
     private static final int SWITCHING_RULE_PRIORITY = 30000;
-    private static final int EAST_WEST_ROUTING_RULE_PRIORITY = 29000;
     private static final int TUNNELTAG_RULE_PRIORITY = 30000;
 
     private FlowObjectiveService flowObjectiveService;
@@ -490,4 +489,5 @@
         }
         return port.number();
     }
+
 }
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index ce6fd7e..ce4fe52 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -84,6 +84,23 @@
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response updatePorts(InputStream input) {
-        return Response.status(Response.Status.OK).build();
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode portNode = (ObjectNode) mapper.readTree(input);
+
+            OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
+            OpenstackSwitchingService switchingService =
+                    getService(OpenstackSwitchingService.class);
+            switchingService.updatePort(openstackPort);
+
+            log.debug("REST API update port is called with {}", portNode.toString());
+            return Response.status(Response.Status.OK).build();
+
+        } catch (Exception e) {
+            log.error("Update Port failed because of exception {}",
+                    e.toString());
+            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
     }
 }
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java
index a8b3861..f7f46a2 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OpenstackPipeline.java
@@ -64,6 +64,7 @@
 
     protected static final int VNI_TABLE = 0;
     protected static final int FORWARDING_TABLE = 1;
+    protected static final int ACL_TABLE = 2;
 
     private static final int DROP_PRIORITY = 0;
     private static final int TIME_OUT = 0;
@@ -136,6 +137,7 @@
     private void initializePipeline() {
         processVniTable(true);
         processForwardingTable(true);
+        processAclTable(true);
     }
 
     private void processVniTable(boolean install) {
@@ -176,6 +178,26 @@
         applyRules(install, flowRule);
     }
 
+    private void processAclTable(boolean install) {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+
+        treatment.wipeDeferred();
+        treatment.drop();
+
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .forDevice(deviceId)
+                .withSelector(selector.build())
+                .withTreatment(treatment.build())
+                .withPriority(DROP_PRIORITY)
+                .fromApp(appId)
+                .makePermanent()
+                .forTable(ACL_TABLE)
+                .build();
+
+        applyRules(install, flowRule);
+    }
+
     private void applyRules(boolean install, FlowRule flowRule) {
         FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
 
@@ -264,8 +286,15 @@
             tBuilder.transition(FORWARDING_TABLE);
             ruleBuilder.withTreatment(tBuilder.build());
             ruleBuilder.forTable(VNI_TABLE);
-        } else {
+        } else if (forwardingObjective.selector().getCriterion(Criterion.Type.TUNNEL_ID) != null) {
+            TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+            tBuilder.deferred();
+            forwardingObjective.treatment().allInstructions().forEach(tBuilder::add);
+            tBuilder.transition(ACL_TABLE);
+            ruleBuilder.withTreatment(tBuilder.build());
             ruleBuilder.forTable(FORWARDING_TABLE);
+        } else {
+            ruleBuilder.forTable(ACL_TABLE);
         }
 
         return Collections.singletonList(ruleBuilder.build());