Added fixed DHCP security rules, which will be added on a VM create.
authorAswin Suryanarayanan <aswin.suryanarayanan@hp.com>
Mon, 6 Jul 2015 14:39:52 +0000 (20:09 +0530)
committerAswin Suryanarayanan <aswin.suryanarayanan@hp.com>
Thu, 16 Jul 2015 21:23:36 +0000 (02:53 +0530)
Change-Id: I8652c986acf3488ddf661ed265bff4cf6fb5ed1e
Signed-off-by: Aswin Suryanarayanan <aswin.suryanarayanan@hp.com>
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/ConfigActivator.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
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/IngressAclProvider.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/api/SecurityServicesManager.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/impl/SecurityServicesImpl.java
utils/mdsal-openflow/src/main/java/org/opendaylight/ovsdb/utils/mdsal/openflow/MatchUtils.java

index efe8aafd05a02f3031efc0ca7bc1b8dbad87b8b6..2f381f418ca61f21f0786e209c446380d5f786e7 100644 (file)
@@ -14,6 +14,9 @@ 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.neutron.spi.NeutronNetwork;
+import org.opendaylight.neutron.spi.NeutronPort;
+import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
@@ -76,6 +79,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -709,6 +713,29 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
         return dpid;
     }
 
+    /**
+     * Returns true is the network if of type GRE or VXLAN
+     *
+     * @param networkType The type of the network
+     * @return returns true if the network is a tunnel
+     */
+    private boolean isTunnel(String networkType)
+    {
+        return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
+                (NetworkHandler.NETWORK_TYPE_VXLAN))? true:false;
+    }
+
+    /**
+     * Returns true if the network is of type vlan.
+     *
+     * @param networkType The type of the network
+     * @return returns true if the network is a vlan
+     */
+    private boolean isVlan(String networkType)
+    {
+        return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)? true:false;
+    }
+
     private void programLocalRules (String networkType, String segmentationId, Node node,
                                     OvsdbTerminationPointAugmentation intf) {
         logger.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
@@ -734,10 +761,35 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
             }
 
             /* Program local rules based on network type */
-            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            if (isVlan(networkType)) {
                 logger.debug("Program local vlan rules for interface {}", intf.getName());
                 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
             }
+            if ((isTunnel(networkType)|| isVlan(networkType))) {
+                logger.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
+                // Get the DHCP port for the subnet to which  the interface belongs to.
+                NeutronPort dhcpPort = securityServicesManager.getDHCPServerPort(intf);
+                if (null != dhcpPort) {
+                    boolean isComputePort =securityServicesManager.isComputePort(intf);
+                    boolean isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
+                    boolean isLastPortinSubnet =false;
+                    List<Neutron_IPs> srcAddressList = null;
+                    if(isComputePort) {
+                        isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
+                        srcAddressList = securityServicesManager.getIpAddress(node, intf);
+                        if (null == srcAddressList) {
+                            logger.warn("programLocalRules: No Ip address assigned {}", intf);
+                            return;
+                        }
+                    }
+                    ingressAclProvider.programFixedSecurityACL(dpid,segmentationId, dhcpPort.getMacAddress(), localPort,
+                            isLastPortinSubnet,isComputePort,  true);
+                    egressAclProvider.programFixedSecurityACL(dpid, segmentationId, attachedMac, localPort,
+                                                              srcAddressList, isLastPortinBridge, isComputePort,true);
+                } else {
+                    logger.warn("programLocalRules: No DCHP port seen in  network of {}", intf);
+                }
+            }
             /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
             /* TODO SB_MIGRATION */
             /*if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
@@ -752,8 +804,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                 egressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
                         securityGroupInPort);
             }*/
-            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
-                    networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
+            if (isTunnel(networkType)) {
                 logger.debug("Program local bridge rules for interface {}, "
                         + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
                         intf.getName(), dpid, segmentationId, attachedMac, localPort);
@@ -788,14 +839,37 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
             }
 
             /* Program local rules based on network type */
-            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            if (isVlan(networkType)) {
                 logger.debug("Remove local vlan rules for interface {}", intf.getName());
                 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
-            } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
-                    networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
+            } else if (isTunnel(networkType)) {
                 logger.debug("Remove local bridge rules for interface {}", intf.getName());
                 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
             }
+            if (isTunnel(networkType)|| isVlan(networkType)) {
+                logger.debug("removeLocalRules: Remove fixed security group rules for interface {}", intf.getName());
+                NeutronPort dhcpPort = securityServicesManager.getDHCPServerPort(intf);
+                if (null != dhcpPort) {
+                    List<Neutron_IPs> srcAddressList = securityServicesManager.getIpAddress(node, intf);
+                    if (null == srcAddressList) {
+                        logger.warn("removeLocalRules: No Ip address assigned {}", intf);
+                        return;
+                    }
+                    boolean isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
+                    boolean isComputePort =securityServicesManager.isComputePort(intf);
+                    boolean isLastPortinSubnet =false;
+                    if (isComputePort)
+                    {
+                        isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
+                    }
+                    ingressAclProvider.programFixedSecurityACL(dpid,   segmentationId, dhcpPort.getMacAddress(), localPort,
+                            isLastPortinSubnet, isComputePort, false);
+                    egressAclProvider.programFixedSecurityACL(dpid, segmentationId,    attachedMac, localPort,
+                                                              srcAddressList, isLastPortinBridge, isComputePort, false);
+                }else{
+                    logger.warn("removeLocalRules: No DCHP port seen in  network of {}", intf);
+                }
+            }
         } catch (Exception e) {
             logger.error("Exception in removing Local Rules for "+intf+" on "+node, e);
         }
@@ -1000,10 +1074,9 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
         Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
         programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
 
-        if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+        if (isVlan(networkType)) {
             programVlanRules(network, srcNode, intf);
-        } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
-                || networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
+        } else if (isTunnel(networkType)){
 
             boolean sourceTunnelStatus = false;
             boolean destTunnelStatus = false;
@@ -1084,10 +1157,9 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
             removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
                     srcNode, intf);
 
-            if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            if (isVlan(network.getProviderNetworkType())) {
                 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
-            } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
-                    || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
+            } else if (isTunnel(network.getProviderNetworkType())) {
 
                 for (Node dstNode : nodes.values()) {
                     InetAddress src = configurationService.getTunnelEndPoint(srcNode);
index fdf4807c08b634467b72b08735ad3390d88a594a..94cd2c372f700762ab75d41330f3288ad45b009d 100644 (file)
 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
 
 import java.math.BigInteger;
+import java.net.InetAddress;
+import java.util.Iterator;
 import java.util.List;
 
 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
 import org.opendaylight.neutron.spi.NeutronSecurityRule;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
@@ -43,6 +46,9 @@ import com.google.common.collect.Lists;
 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
 
     static final Logger logger = LoggerFactory.getLogger(EgressAclService.class);
+    final int DHCP_SOURCE_PORT = 67;
+    final int DHCP_DESTINATION_PORT = 68;
+    final String HOST_MASK = "/32";
 
     public EgressAclService() {
         super(Service.EGRESS_ACL);
@@ -219,6 +225,24 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         }
     }
 
+    @Override
+    public void programFixedSecurityACL(Long dpid, String segmentationId, String attachedMac,
+            long localPort, List<Neutron_IPs> srcAddressList, boolean isLastPortinBridge, boolean isComputePort ,boolean write) {
+        // If it is the only port in the bridge add the rule to allow any DHCP client traffic
+        if (isLastPortinBridge) {
+            egressACLDHCPAllowClientTrafficFromVm(dpid, write, Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
+        }
+        if(isComputePort) {
+        // add rule to drop the DHCP server traffic originating from the vm.
+            egressACLDHCPDropServerTrafficfromVM(dpid, localPort, write, Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
+            //Adds rule to check legitimate ip/mac pair for each packet from the vm
+            for(Neutron_IPs srcAddress : srcAddressList) {
+                String addressWithPrefix = srcAddress.getIpAddress() + HOST_MASK;
+                egressACLAllowTrafficFromVmIpMacPair(dpid, localPort, attachedMac, addressWithPrefix, Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
+            }
+        }
+    }
+
     public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
                                         int priority, boolean write) {
 
@@ -470,6 +494,165 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
         }
     }
 
+    /**
+     * Adds flow to allow any DHCP client traffic
+     *
+     * @param dpidLong the dpid
+     * @param write whether to write or delete the flow
+     * @param protoPortMatchPriority the priority
+     */
+    public void egressACLDHCPAllowClientTrafficFromVm(Long dpidLong,
+            boolean write, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createDHCPMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT).build());
+        logger.debug("egressACLDHCPAllowClientTrafficFromVm: MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Egress_DHCP_Client"  + "_Permit_";
+        // 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("egressACLDHCPAllowClientTrafficFromVm: Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /**
+     * Adds rule to prevent DHCP spoofing by the vm attached to the port.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param write is write or delete
+     * @param protoPortMatchPriority  the priority
+     */
+    public void egressACLDHCPDropServerTrafficfromVM(Long dpidLong, long localPort,
+            boolean write, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        flowBuilder.setMatch(MatchUtils.createDHCPMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT).build());
+
+        logger.debug("egressACLDHCPDropServerTrafficfromVM: MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
+        // 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();
+
+            InstructionUtils.createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructionsList.add(ib.build());
+            isb.setInstruction(instructionsList);
+
+            logger.debug("egressACLDHCPDropServerTrafficfromVM: Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /**
+     * Adds rule to check legitimate ip/mac pair for each packet from the vm.
+     *
+     * @param dpidLong the dpid
+     * @param localPort the local port
+     * @param srcIp the vm ip address
+     * @param attachedMac the vm mac address
+     * @param protoPortMatchPriority  the priority
+     * @param write is write or delete
+     */
+    public void egressACLAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
+             String attachedMac, String srcIp, Integer protoPortMatchPriority, boolean write) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+        MatchUtils.createSrcL3IPv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
+        MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
+        flowBuilder.setMatch(matchBuilder.build());
+
+        logger.debug("egressACLAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
+        // 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("egressACLAllowTrafficFromVmIpMacPair: Instructions contain: {}", ib.getInstruction());
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
     @Override
     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
         super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
index 68da745fb251ac11f885606c60baab53b43c424d..9828a27fe6aeed9e70aaf0b7926f53cb14fc17ee 100644 (file)
@@ -208,6 +208,15 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         }
     }
 
+    @Override
+    public void programFixedSecurityACL(Long dpid, String segmentationId, String dhcpMacAddress,
+          long localPort, boolean isLastPortinSubnet, boolean isComputePort, boolean write){
+         //If this port is the only port in the compute node add the DHCP server rule.
+        if (isLastPortinSubnet && isComputePort ) {
+            ingressACLDHCPAllowServerTraffic(dpid, segmentationId,dhcpMacAddress, write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
+        }
+    }
+
     public void ingressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
             Integer securityRulePortMin, Integer protoPortMatchPriority) {
 
@@ -464,6 +473,58 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
         }
     }
 
+    /**
+     * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
+     *
+     * @param dpidLong the dpid
+     * @param segmentationId the segmentation id
+     * @param dhcpMacAddress the DHCP server mac address
+     * @param write is write or delete
+     * @param protoPortMatchPriority the priority
+     */
+    private void ingressACLDHCPAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
+            boolean write, Integer protoPortMatchPriority) {
+
+        String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        flowBuilder.setMatch(MatchUtils.createDHCPServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build());
+        logger.debug("ingressACLDHCPAllowServerTraffic: MatchBuilder contains: {}", flowBuilder.getMatch());
+        String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
+        // 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);
+        }
+    }
     @Override
     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
         super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
index b29c53346e543cd7acc54e7901e28aa80b1526a5..56ce63e70d58611ee0a12c391155496b3e2dc9a6 100644 (file)
@@ -249,6 +249,7 @@ public class ConfigActivator implements BundleActivator {
                     lBaaSHandler.setDependencies(service);
                     lBaaSPoolHandler.setDependencies(service);
                     lBaaSPoolMemberHandler.setDependencies(service);
+                    securityServices.setDependencies(service);
                     neutronL3Adapter.setDependencies(service);
                 }
                 return service;
index 4016e3b503f2780cad4fe64bfab91498f44ccd98..05a9a0728c49acb5fa56ca466805e12883c735ce 100644 (file)
@@ -77,6 +77,7 @@ public final class Constants {
     /*
      * ACL
      */
+    public static final Integer PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP = 61011;
     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;
@@ -84,11 +85,14 @@ public final class Constants {
     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_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY = 61012;
     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 Integer PROTO_DHCP_SERVER_MATCH_PRIORITY = 61006;
+    public static final Integer PROTO_VM_IP_MAC_MATCH_PRIORITY = 36001;
 
     public static final int TCP_SYN = 0x002;
     public static final short INGRESS_ACL = 40; // Flows Destined to the VM Port go here
index 315a7846c9bd9dda50ca789cd9378b6ad3aafd5b..4747ad20e54da45e6e1a813a4888fed4f4ddb386 100644 (file)
@@ -1,6 +1,9 @@
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
+import java.util.List;
+
 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 
 /**
  *  This interface allows egress Port Security flows to be written to devices
@@ -18,4 +21,18 @@ public interface EgressAclProvider {
      */
     public void programPortSecurityACL(Long dpid, String segmentationId, String attachedMac,
                                        long localPort, NeutronSecurityGroup securityGroup);
+    /**
+     *  Program fixed egress ACL rules that will be associated with the VM port when a vm is spawned.
+     *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param srcAddressList the list of source ip address assigned to vm
+     * @param isLastPortinBridge is this the last port in the bridge
+     * @param isComputePort indicates whether this port is a compute port or not
+     * @param write is this flow writing or deleting
+     */
+    public void programFixedSecurityACL(Long dpid, String segmentationId,String attachedMac,
+            long localPort, List<Neutron_IPs> srcAddressList, boolean isLastPortinBridge, boolean isComputePort, boolean write);
 }
index 7a0d0ae10ff6c2bdf2076df2edbcbcab61e4b00e..a8594595fd6cf45984e6a40b6b831a600d3682ad 100644 (file)
@@ -27,4 +27,17 @@ public interface IngressAclProvider {
      */
     public void programPortSecurityACL(Long dpid, String segmentationId, String attachedMac,
             long localPort, NeutronSecurityGroup securityGroup);
+    /**
+     * Program fixed ingress ACL rules that will be associated with the VM port when a vm is spawned.
+     * *
+     * @param dpid the dpid
+     * @param segmentationId the segmentation id
+     * @param attachedMac the attached mac
+     * @param localPort the local port
+     * @param isLastPortinSubnet is this the last port in the subnet
+     * @param isComputePort indicates whether this port is a compute port or not
+     * @param write is this flow writing or deleting
+     */
+    public void programFixedSecurityACL(Long dpid, String segmentationId,
+            String attachedMac, long localPort, boolean isLastPortinSubnet, boolean isComputePort, boolean write);
 }
index 785d54be001c1723a03a81d645f98a1a10aa1ecd..49d255b98be0de92af056bb7fa46f71ec9aea1b6 100644 (file)
@@ -9,8 +9,13 @@
 
 package org.opendaylight.ovsdb.openstack.netvirt.api;
 
+import java.util.List;
+
+import org.opendaylight.neutron.spi.NeutronPort;
 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 
 /**
  * Open vSwitch isolates Tenant Networks using VLANs on the Integration Bridge
@@ -31,5 +36,42 @@ public interface SecurityServicesManager {
      * @return the security group in port
      */
     public NeutronSecurityGroup getSecurityGroupInPort(OvsdbTerminationPointAugmentation intf);
+     /**
+     * Gets the DHCP server port corresponding to a network.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public NeutronPort getDHCPServerPort(OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Is the port a compute port.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public boolean isComputePort(OvsdbTerminationPointAugmentation intf);
 
+    /**
+     * Is this the last port in the subnet to which interface belongs to.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation intf);
+
+    /**
+     * Is this the last port in the bridge to which interface belongs to.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation intf);
+    /**
+     * Returns the  list of ip adddress assigned to the interface.
+     *
+     * @param intf the intf
+     * @return the security group in port
+     */
+    public List<Neutron_IPs> getIpAddress(Node node, OvsdbTerminationPointAugmentation intf);
 }
\ No newline at end of file
index f861f53aafd0e5d59f79b9a44f7b7ce5776aec04..c29e7adc52f85060d48f12ef734bd593bfaffc46 100644 (file)
@@ -8,15 +8,23 @@
 package org.opendaylight.ovsdb.openstack.netvirt.impl;
 
 import java.util.List;
+
 import org.opendaylight.neutron.spi.INeutronPortCRUD;
+import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
 import org.opendaylight.neutron.spi.NeutronPort;
 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
+import org.opendaylight.neutron.spi.NeutronSubnet;
+import org.opendaylight.neutron.spi.Neutron_IPs;
 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.*;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.node.attributes.SupportingNode;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
@@ -25,6 +33,7 @@ import org.slf4j.LoggerFactory;
 public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
     static final Logger logger = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
     private volatile INeutronPortCRUD neutronPortCache;
+    private volatile INeutronSubnetCRUD neutronSubnetCache;
     private volatile Southbound southbound;
 
     /**
@@ -96,6 +105,152 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
         }
     }
 
+    @Override
+    public NeutronPort getDHCPServerPort(
+            OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            logger.error("getDHCPServerPort: neutron port is null");
+            return null;
+        }
+        logger.trace("getDHCPServerPort for {}",
+                terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(
+                terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return null;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        //Since all the fixed ip assigned to a port should be from the same network, first port is sufficient.
+        List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
+        if(null==fixedIps || 0 == fixedIps.size() )
+        {
+            logger.error("getDHCPServerPort: No fixed ip is assigned");
+            return null;
+        }
+        String subnetUUID = fixedIps.iterator().next().getSubnetUUID();
+        NeutronSubnet neutronSubnet = neutronSubnetCache.getSubnet(subnetUUID);
+        List<NeutronPort> ports = neutronSubnet.getPortsInSubnet();
+        for (NeutronPort port : ports) {
+            if (port.getDeviceOwner().contains("dhcp")) {
+                return port;
+            }
+        }
+
+        return null;
+
+    }
+
+    @Override
+    public boolean isComputePort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            logger.error("neutron port is null");
+            return false;
+        }
+        logger.trace("isComputePort for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return false;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        if (neutronPort == null) {
+            return false;
+        }
+        String deviceOwner = neutronPort.getDeviceOwner();
+        if (!deviceOwner.contains("compute")) {
+            logger.debug("isComputePort : Port {} is not a DHCP server port", neutronPortId,deviceOwner);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            logger.error("isLastPortinSubnet: neutron port is null");
+            return false;
+        }
+        logger.trace("isLastPortinSubnet: for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return false;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        List<Neutron_IPs> neutronPortFixedIp = neutronPort.getFixedIPs();
+        if(null == neutronPortFixedIp || neutronPortFixedIp.isEmpty()) {
+            return false;
+        }
+        List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+        if(terminationPoints != null && !terminationPoints.isEmpty()) {
+            for(TerminationPoint tp : terminationPoints) {
+                OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                        tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (ovsdbTerminationPointAugmentation != null && !ovsdbTerminationPointAugmentation.
+                        getName().equals(Constants.INTEGRATION_BRIDGE)) {
+                    String portId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
+                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
+                    if(null!=portId) {
+                        NeutronPort port = neutronPortCache.getPort(portId);
+                        if(null!=port) {
+                            if(!(port.getID().equals(neutronPort.getID())) && port.getDeviceOwner().contains("compute")) {
+                                List<Neutron_IPs> portFixedIp = port.getFixedIPs();
+                                if(null == portFixedIp || portFixedIp.isEmpty()) {
+                                    return false;
+                                }
+                                if(portFixedIp.iterator().next().getSubnetUUID().equals
+                                        (neutronPort.getFixedIPs().iterator().next().getSubnetUUID())) {
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        logger.trace("isLastPortinBridge: for {}", terminationPointAugmentation.getName());
+        List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+        if(terminationPoints != null && !terminationPoints.isEmpty()){
+            for(TerminationPoint tp : terminationPoints){
+                OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                        tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if(null!=ovsdbTerminationPointAugmentation)
+                {
+                    if(!(ovsdbTerminationPointAugmentation.getName().equals(Constants.INTEGRATION_BRIDGE))
+                            && !(terminationPointAugmentation.getInterfaceUuid().equals
+                                    (ovsdbTerminationPointAugmentation.getInterfaceUuid()))) {
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public List<Neutron_IPs> getIpAddress(Node node,
+                                OvsdbTerminationPointAugmentation terminationPointAugmentation) {
+        if (neutronPortCache == null) {
+            logger.error("getIpAddress: neutron port is null");
+            return null;
+        }
+        logger.trace("getIpAddress: for {}", terminationPointAugmentation.getName());
+        String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
+                Constants.EXTERNAL_ID_INTERFACE_ID);
+        if (neutronPortId == null) {
+            return null;
+        }
+        NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
+        List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
+        return fixedIps;
+    }
+
     @Override
     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
         southbound =
@@ -107,5 +262,8 @@ public class SecurityServicesImpl implements ConfigInterface, SecurityServicesMa
         if (impl instanceof INeutronPortCRUD) {
             neutronPortCache = (INeutronPortCRUD)impl;
         }
+        else if (impl instanceof INeutronSubnetCRUD) {
+            neutronSubnetCache = (INeutronSubnetCRUD) impl;
+        }
     }
 }
index 8ed4b5bc30a75601b7aa395af2112f94b2c42233..4e190003208a826c21088350fb965904a4d69c7b 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
@@ -893,6 +894,95 @@ public class MatchUtils {
         return matchBuilder;
     }
 
+    /**
+     * Create a DHCP match with pot provided
+     *
+     * @param matchBuilder the match builder
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP match
+     */
+    public static MatchBuilder createDHCPMatch(MatchBuilder matchBuilder, int srcPort, int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * Creates DHCP server packet match with DHCP mac address and port.
+     *
+     * @param matchBuilder the matchbuilder
+     * @param dhcpServerMac MAc address of the DHCP server of the subnet
+     * @param srcPort the source port
+     * @param dstPort the destination port
+     * @return the DHCP server match
+     */
+    public static MatchBuilder createDHCPServerMatch(MatchBuilder matchBuilder, String dhcpServerMac, int srcPort,
+            int dstPort) {
+
+        EthernetMatchBuilder ethernetMatch = new EthernetMatchBuilder();
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        ethernetMatch.setEthernetType(ethTypeBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        EthernetSourceBuilder ethSourceBuilder = new EthernetSourceBuilder();
+        ethSourceBuilder.setAddress(new MacAddress(dhcpServerMac));
+        ethernetMatch.setEthernetSource(ethSourceBuilder.build());
+        matchBuilder.setEthernetMatch(ethernetMatch.build());
+
+        IpMatchBuilder ipmatch = new IpMatchBuilder();
+        ipmatch.setIpProtocol(UDP_SHORT);
+        matchBuilder.setIpMatch(ipmatch.build());
+
+        UdpMatchBuilder udpmatch = new UdpMatchBuilder();
+        udpmatch.setUdpSourcePort(new PortNumber(srcPort));
+        udpmatch.setUdpDestinationPort(new PortNumber(dstPort));
+        matchBuilder.setLayer4Match(udpmatch.build());
+
+        return matchBuilder;
+
+    }
+
+    /**
+     * @param matchBuilder MatchBuilder Object
+     * @param srcip String containing an IPv4 prefix
+     * @param srcMac The source macAddress
+     * @return matchBuilder Map Object with a match
+     */
+    public static MatchBuilder createSrcL3IPv4MatchWithMac(MatchBuilder matchBuilder, Ipv4Prefix srcip, MacAddress srcMac) {
+
+        Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
+        ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(srcip));
+        EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
+        ethTypeBuilder.setType(new EtherType(0x0800L));
+        EthernetMatchBuilder eth = new EthernetMatchBuilder();
+        eth.setEthernetType(ethTypeBuilder.build());
+        eth.setEthernetSource(new EthernetSourceBuilder()
+                .setAddress(srcMac)
+                .build());
+
+        matchBuilder.setLayer3Match(ipv4MatchBuilder.build());
+        matchBuilder.setEthernetMatch(eth.build());
+        return matchBuilder;
+
+    }
+
     public static class RegMatch {
         final Class<? extends NxmNxReg> reg;
         final Long value;