Bug 9022: ACL: Broadcast traffic is dropped in ACL tables 51/62151/1
authorShashidhar Raja <shashidharr@altencalsoftlabs.com>
Mon, 21 Aug 2017 14:20:21 +0000 (19:50 +0530)
committerVivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Tue, 22 Aug 2017 11:59:57 +0000 (11:59 +0000)
This fix enables ACL to permit Broadcast Traffic (Both IP and Non IP).

Related to IP Broadcast, Subnet-Directed Broadcast and All-Subnet
Broadcast traffic on the same network is being allowed subject to one of
the conditions specified below is met:
  (a) The ports that want to communicate share the same
      remote-secuirty-group
  (b) The ports that want to communicate allow the other port's IP Address
      in remote-ip-prefix
  (c) The ports that want to communicate have securiyt0group with
      remote-ip-prefix of 0.0.0.0/0.

IP Broadcast flows configured in VM Ingress ACL table (table 241) is as
below:

all-subnet flow:
cookie=0x6900000, duration=1463.293s, table=241, n_packets=0, n_bytes=0,
       priority=61010,ip,dl_dst=ff:ff:ff:ff:ff:ff,nw_dst=255.255.255.255
       actions=goto_table:242

subnet-directed flow:
cookie=0x6900000, duration=975.798s, table=241, n_packets=0, n_bytes=0,
       priority=61010,ip,metadata=0x10000000000/0x1fffff0000000000,
       dl_dst=ff:ff:ff:ff:ff:ff,nw_dst=10.1.1.255 actions=goto_table:242

Non IP Broadcast flows (with lower priority than other flows - 61005)
configured in VM Egress(211) and Ingress(241) tables is as below:

cookie=0x6900000, duration=30.298s, table=211, n_packets=0, n_bytes=0,
       priority=61005,metadata=0x10000000000/0x1fffff0000000000,
       dl_src=fa:16:3e:a9:4d:81 actions=resubmit(,17)

cookie=0x6900000, duration=901.855s, table=241, n_packets=0, n_bytes=0,
       priority=61005,dl_dst=ff:ff:ff:ff:ff:ff actions=resubmit(,220)

Below are change details:
 - Updated to add a flow to allow broadcast traffic with destination
   adddress 255.255.255.255. Changes related to this are in
   AclNodeListener.java
 - Updated to add flows at port level for subnetwork's broadcast addresses
 - Updated to add flows in 211/241 for Non-IP broadcast traffic
 - Updated to add ARP/IP/IPv6 default drop flows with lower priority than
   respective flows and higher priority than non-ip broadcast flow
 - New yang definition introduced in ACL for higher modules (Neutron VPN
   in our case) to pass broadcast CIDRs when ACL Interface is created
 - NeutronVpn is updated to pass subnet CIDRs when ACL Interface is
   created

Change-Id: I71c5040454b3c00af43dcef4f47b5979cd7cf3a5
Signed-off-by: Shashidhar Raja <shashidharr@altencalsoftlabs.com>
17 files changed:
vpnservice/aclservice/api/src/main/java/org/opendaylight/netvirt/aclservice/api/utils/AclInterface.java
vpnservice/aclservice/api/src/main/yang/aclservice.yang
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/AbstractAclServiceImpl.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/AbstractEgressAclServiceImpl.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/AbstractIngressAclServiceImpl.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/TransparentEgressAclServiceImpl.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/TransparentIngressAclServiceImpl.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/listeners/AclInterfaceListener.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/listeners/AclInterfaceStateListener.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/listeners/AclNodeListener.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/utils/AclConstants.java
vpnservice/aclservice/impl/src/main/java/org/opendaylight/netvirt/aclservice/utils/AclServiceUtils.java
vpnservice/aclservice/impl/src/test/java/org/opendaylight/netvirt/aclservice/tests/FlowEntryObjectsBase.xtend
vpnservice/aclservice/impl/src/test/java/org/opendaylight/netvirt/aclservice/tests/FlowEntryObjectsStateful.xtend
vpnservice/aclservice/impl/src/test/java/org/opendaylight/netvirt/aclservice/tests/FlowEntryObjectsStateless.xtend
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronPortChangeListener.java
vpnservice/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnUtils.java

index d71347efc7ab302ace524677b1feaeb933619a45..63ff86118d3a3b3e111522b0319d398a9688cb46 100644 (file)
@@ -11,6 +11,7 @@ import java.math.BigInteger;
 import java.util.List;
 
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
 
 /**
@@ -42,6 +43,9 @@ public class AclInterface {
     /** The allowed address pairs. */
     List<AllowedAddressPairs> allowedAddressPairs;
 
+    /** The IP broadcast CIDRs. */
+    List<IpPrefixOrAddress> subnetIpPrefixes;
+
     /** The port is marked for delete. */
     Boolean isMarkedForDelete = false;
 
@@ -198,6 +202,24 @@ public class AclInterface {
         this.allowedAddressPairs = allowedAddressPairs;
     }
 
+    /**
+     * Gets the Subnet IP Prefix.
+     *
+     * @return the Subnet IP Prefix
+     */
+    public List<IpPrefixOrAddress> getSubnetIpPrefixes() {
+        return subnetIpPrefixes;
+    }
+
+    /**
+     * Sets the Subnet IP Prefix.
+     *
+     * @param subnetIpPrefixes the Subnet IP Prefix
+     */
+    public void setSubnetIpPrefixes(List<IpPrefixOrAddress> subnetIpPrefixes) {
+        this.subnetIpPrefixes = subnetIpPrefixes;
+    }
+
     /**
      * Retrieve isMarkedForDelete.
      * @return the whether it is marked for delete
index 6416691d4dbf0a8532f27524a13be9bc5f955b9a..fa19745be7ca90f96116a2f3f8c23acac03e17a7 100644 (file)
@@ -80,4 +80,18 @@ module aclservice {
             }
         }
     }
+
+    container ports-subnet-ip-prefixes {
+        list port-subnet-ip-prefixes {
+            key port-id;
+            leaf port-id {
+                type string;
+                description "Port ID";
+            }
+            leaf-list subnet-ip-prefixes {
+                type ip-prefix-or-address;
+                description "Subnet IP Prefixes of the Port.";
+            }
+        }
+    }
 }
index 817c10ba2833d35997b2d2a091f8c8dde7dcda17..61914f3f937d5b65dc36f20b095120d809dc7115 100644 (file)
@@ -168,6 +168,9 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         }
         updateArpForAllowedAddressPairs(dpId, portAfter.getLPortTag(), deletedAllowedAddressPairs,
                 portAfter.getAllowedAddressPairs());
+        if (portAfter.getSubnetIpPrefixes() != null && portBefore.getSubnetIpPrefixes() == null) {
+            programBroadcastRules(portAfter, NwConstants.ADD_FLOW);
+        }
 
         updateAclInterfaceInCache(portBefore);
         // Have to delete and add all rules because there can be following scenario: Interface1 with SG1, Interface2
@@ -231,7 +234,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         LOG.debug("Applying ACL Allowed Address on DpId {}, lportTag {}, Action {}", dpId, lportTag, action);
         List<Uuid> aclUuidList = port.getSecurityGroups();
         String portId = port.getInterfaceId();
-        programGeneralFixedRules(dpId, "", allowedAddresses, lportTag, action, addOrRemove);
+        programGeneralFixedRules(port, "", allowedAddresses, action, addOrRemove);
         programSpecificFixedRules(dpId, "", allowedAddresses, lportTag, portId, action, addOrRemove);
         if (action == Action.ADD || action == Action.REMOVE) {
             programAclRules(port, aclUuidList, addOrRemove);
@@ -289,15 +292,14 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     /**
      * Program the default anti-spoofing rules.
      *
-     * @param dpid the dpid
+     * @param port the acl interface
      * @param dhcpMacAddress the dhcp mac address.
      * @param allowedAddresses the allowed addresses
-     * @param lportTag the lport tag
      * @param action add/modify/remove action
      * @param addOrRemove addorRemove
      */
-    protected abstract void programGeneralFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action, int addOrRemove);
+    protected abstract void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+            List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove);
 
     /**
      * Update arp for allowed address pairs.
@@ -346,6 +348,14 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     protected abstract void programAceRule(AclInterface port, int addOrRemove, String aclName, Ace ace,
             List<AllowedAddressPairs> syncAllowedAddresses);
 
+    /**
+     * Programs broadcast rules.
+     *
+     * @param port the Acl Interface port
+     * @param addOrRemove whether to delete or add flow
+     */
+    protected abstract void programBroadcastRules(AclInterface port, int addOrRemove);
+
     /**
      * Writes/remove the flow to/from the datastore.
      *
index 5229b37209d90b0488412d9ba0f014f443108ed3..fe075b0cb4734b7757d0c6d01385a50773404fa2 100644 (file)
@@ -157,10 +157,12 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
     }
 
     @Override
-    protected void programGeneralFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action, int addOrRemove) {
+    protected void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+            List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
         LOG.info("programFixedRules : {} default rules.", action == Action.ADD ? "adding" : "removing");
 
+        BigInteger dpid = port.getDpId();
+        int lportTag = port.getLPortTag();
         if (action == Action.ADD || action == Action.REMOVE) {
             Set<MacAddress> aapMacs =
                 allowedAddresses.stream().map(aap -> aap.getMacAddress()).collect(Collectors.toSet());
@@ -172,6 +174,7 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
             egressAclIcmpv6AllowedList(dpid, lportTag, addOrRemove);
 
             programArpRule(dpid, allowedAddresses, lportTag, addOrRemove);
+            programL2BroadcastAllowRule(port, addOrRemove);
         }
     }
 
@@ -435,6 +438,42 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
         }
     }
 
+    /**
+     * Programs broadcast rules.
+     *
+     * @param port the Acl Interface port
+     * @param addOrRemove whether to delete or add flow
+     */
+    @Override
+    protected void programBroadcastRules(AclInterface port, int addOrRemove) {
+        programL2BroadcastAllowRule(port, addOrRemove);
+    }
+
+    /**
+     * Programs Non-IP broadcast rules.
+     *
+     * @param port the Acl Interface port
+     * @param addOrRemove whether to delete or add flow
+     */
+    private void programL2BroadcastAllowRule(AclInterface port, int addOrRemove) {
+        BigInteger dpId = port.getDpId();
+        int lportTag = port.getLPortTag();
+        List<AllowedAddressPairs> allowedAddresses = port.getAllowedAddressPairs();
+        Set<MacAddress> macs = allowedAddresses.stream().map(aap -> aap.getMacAddress()).collect(Collectors.toSet());
+        for (MacAddress mac : macs) {
+            List<MatchInfoBase> matches = new ArrayList<>();
+            matches.add(new MatchEthernetSource(mac));
+            matches.add(buildLPortTagMatch(lportTag));
+
+            List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(new ArrayList<>());
+
+            String flowName = "Egress_L2Broadcast_" + dpId + "_" + lportTag + "_" + mac.getValue();
+            syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName,
+                    AclConstants.PROTO_L2BROADCAST_TRAFFIC_MATCH_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE,
+                    matches, instructions, addOrRemove);
+        }
+    }
+
     protected MatchInfoBase buildLPortTagMatch(int lportTag) {
         return AclServiceUtils.buildLPortTagMatch(lportTag, ServiceModeEgress.class);
     }
index 411584b060532f33ab5a749c5791818f26fdffdb..2960991da63832c0b51c706bba9cebfbc8da5876 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -164,10 +165,12 @@ public abstract class AbstractIngressAclServiceImpl extends AbstractAclServiceIm
             List<AllowedAddressPairs> allowedAddresses, int lportTag, String portId, Action action, int addOrRemove);
 
     @Override
-    protected void programGeneralFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action, int addOrRemove) {
+    protected void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+            List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
         LOG.info("programFixedRules : {} default rules.", action == Action.ADD ? "adding" : "removing");
 
+        BigInteger dpid = port.getDpId();
+        int lportTag = port.getLPortTag();
         if (action == Action.ADD || action == Action.REMOVE) {
             ingressAclDhcpAllowServerTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove,
                     AclConstants.PROTO_PREFIX_MATCH_PRIORITY);
@@ -176,6 +179,7 @@ public abstract class AbstractIngressAclServiceImpl extends AbstractAclServiceIm
             ingressAclIcmpv6AllowedTraffic(dpid, lportTag, addOrRemove);
 
             programArpRule(dpid, lportTag, addOrRemove);
+            programIpv4BroadcastRule(port, addOrRemove);
         }
     }
 
@@ -380,6 +384,47 @@ public abstract class AbstractIngressAclServiceImpl extends AbstractAclServiceIm
                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
     }
 
+
+    /**
+     * Programs broadcast rules.
+     *
+     * @param port the Acl Interface port
+     * @param addOrRemove whether to delete or add flow
+     */
+    @Override
+    protected void programBroadcastRules(AclInterface port, int addOrRemove) {
+        programIpv4BroadcastRule(port, addOrRemove);
+    }
+
+    /**
+     * Programs IPv4 broadcast rules.
+     *
+     * @param port the Acl Interface port
+     * @param addOrRemove whether to delete or add flow
+     */
+    private void programIpv4BroadcastRule(AclInterface port, int addOrRemove) {
+        BigInteger dpId = port.getDpId();
+        int lportTag = port.getLPortTag();
+        MatchInfoBase lportMatchInfo = buildLPortTagMatch(lportTag);
+        List<IpPrefixOrAddress> cidrs = port.getSubnetIpPrefixes();
+        if (cidrs != null) {
+            List<String> broadcastAddresses = AclServiceUtils.getIpBroadcastAddresses(cidrs);
+            for (String broadcastAddress : broadcastAddresses) {
+                List<MatchInfoBase> matches =
+                        AclServiceUtils.buildBroadcastIpV4Matches(broadcastAddress);
+                matches.add(lportMatchInfo);
+                List<InstructionInfo> instructions = new ArrayList<>();
+                instructions.add(new InstructionGotoTable(NwConstants.EGRESS_ACL_REMOTE_ACL_TABLE));
+                String flowName = "Ingress_v4_Broadcast_" + dpId + "_" + lportTag + "_" + broadcastAddress + "_Permit";
+                syncFlow(dpId, NwConstants.EGRESS_ACL_TABLE, flowName,
+                        AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
+                        instructions, addOrRemove);
+            }
+        } else {
+            LOG.error("IP Broadcast CIDRs are missing for port {}", port.getInterfaceId());
+        }
+    }
+
     protected MatchInfoBase buildLPortTagMatch(int lportTag) {
         return AclServiceUtils.buildLPortTagMatch(lportTag, ServiceModeIngress.class);
     }
index 3bad4869c8933dbd0b54f2f78785a5e17958cb66..3efe26c55d2c6d6366daeb114896495d620c5794 100644 (file)
@@ -47,8 +47,8 @@ public class TransparentEgressAclServiceImpl extends AbstractEgressAclServiceImp
     }
 
     @Override
-    protected void programGeneralFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action,
+    protected void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+            List<AllowedAddressPairs> allowedAddresses, Action action,
             int addOrRemove) {
         LOG.debug("transparent egress acl service - do nothing");
     }
index f5dd8a65e961cb732d2ed73cd243dbd9165e1c20..6d3e0c64f3dc1831e40c28a03e1b74253e59584e 100644 (file)
@@ -50,8 +50,8 @@ public class TransparentIngressAclServiceImpl extends AbstractIngressAclServiceI
     }
 
     @Override
-    protected void programGeneralFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action,
+    protected void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+            List<AllowedAddressPairs> allowedAddresses, Action action,
             int addOrRemove) {
         LOG.debug("transparent ingress acl service - do nothing");
     }
index c4397dcfb62b4861c573eb10d00dcdce6b92468e..9b6f84aa34e7d40a63903f8aa2727e1b060c2264 100644 (file)
@@ -26,6 +26,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -72,6 +73,7 @@ public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interf
             if (aclClusterUtil.isEntityOwner()) {
                 LOG.debug("On remove event, notify ACL service manager to unbind ACL from interface: {}", port);
                 aclServiceManager.notify(aclInterface, null, Action.UNBIND);
+                AclServiceUtils.deleteSubnetIpPrefixes(dataBroker, interfaceId);
             }
         }
         AclInterfaceCacheUtil.removeAclInterfaceFromCache(interfaceId);
@@ -88,7 +90,9 @@ public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interf
             if (aclInterface != null) {
                 aclInterface = getOldAclInterfaceObject(aclInterface, aclInPortAfter);
             } else {
-                aclInterface = addAclInterfaceToCache(interfaceId, aclInPortAfter);
+                List<IpPrefixOrAddress> subnetIpPrefixes = AclServiceUtils.getSubnetIpPrefixes(dataBroker,
+                        portAfter.getName());
+                aclInterface = addAclInterfaceToCache(interfaceId, aclInPortAfter, subnetIpPrefixes);
             }
 
             AclInterface oldAclInterface = getOldAclInterfaceObject(aclInterface, aclInPortBefore);
@@ -118,6 +122,7 @@ public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interf
             oldAclInterface.setInterfaceId(aclInterface.getInterfaceId());
             oldAclInterface.setDpId(aclInterface.getDpId());
             oldAclInterface.setLPortTag(aclInterface.getLPortTag());
+            oldAclInterface.setSubnetIpPrefixes(aclInterface.getSubnetIpPrefixes());
             oldAclInterface.setElanId(aclInterface.getElanId());
             oldAclInterface.setVpnId(aclInterface.getVpnId());
 
@@ -132,7 +137,8 @@ public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interf
     protected void add(InstanceIdentifier<Interface> key, Interface port) {
         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
         if (aclInPort != null && aclInPort.isPortSecurityEnabled()) {
-            AclInterface aclInterface = addAclInterfaceToCache(port.getName(), aclInPort);
+            List<IpPrefixOrAddress> subnetIpPrefixes = AclServiceUtils.getSubnetIpPrefixes(dataBroker, port.getName());
+            AclInterface aclInterface = addAclInterfaceToCache(port.getName(), aclInPort, subnetIpPrefixes);
             if (aclClusterUtil.isEntityOwner()) {
                 LOG.debug("On add event, notify ACL service manager to bind ACL for interface: {}", port);
                 aclServiceManager.notify(aclInterface, null, Action.BIND);
@@ -140,18 +146,21 @@ public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interf
         }
     }
 
-    private AclInterface addAclInterfaceToCache(String interfaceId, InterfaceAcl aclInPort) {
-        AclInterface aclInterface = buildAclInterfaceState(interfaceId, aclInPort);
+    private AclInterface addAclInterfaceToCache(String interfaceId, InterfaceAcl aclInPort,
+            List<IpPrefixOrAddress> subnetIpPrefixes) {
+        AclInterface aclInterface = buildAclInterfaceState(interfaceId, aclInPort, subnetIpPrefixes);
         AclInterfaceCacheUtil.addAclInterfaceToCache(interfaceId, aclInterface);
         return aclInterface;
     }
 
-    private AclInterface buildAclInterfaceState(String interfaceId, InterfaceAcl aclInPort) {
+    private AclInterface buildAclInterfaceState(String interfaceId, InterfaceAcl aclInPort,
+            List<IpPrefixOrAddress> subnetIpPrefixes) {
         AclInterface aclInterface = new AclInterface();
         aclInterface.setInterfaceId(interfaceId);
         aclInterface.setPortSecurityEnabled(aclInPort.isPortSecurityEnabled());
         aclInterface.setSecurityGroups(aclInPort.getSecurityGroups());
         aclInterface.setAllowedAddressPairs(aclInPort.getAllowedAddressPairs());
+        aclInterface.setSubnetIpPrefixes(subnetIpPrefixes);
         aclInterface.setElanId(AclServiceUtils.getElanIdFromInterface(interfaceId, dataBroker));
         aclInterface.setVpnId(AclServiceUtils.getVpnIdFromInterface(dataBroker, interfaceId));
         return aclInterface;
index 299236ca2b6eddf5fbe444f377cc626afe9fe4fe..12fa6cdc8a777a40ae2425200270685f2d3fa673 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.re
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -108,6 +109,12 @@ public class AclInterfaceStateListener extends AsyncDataTreeChangeListenerBase<I
         }
         AclInterface aclInterface = updateAclInterfaceCache(added);
         if (AclServiceUtils.isOfInterest(aclInterface)) {
+            if (aclInterface.getSubnetIpPrefixes() == null) {
+                // For upgrades
+                List<IpPrefixOrAddress> subnetIpPrefixes = AclServiceUtils.getSubnetIpPrefixes(dataBroker,
+                        added.getName());
+                aclInterface.setSubnetIpPrefixes(subnetIpPrefixes);
+            }
             List<Uuid> aclList = aclInterface.getSecurityGroups();
             if (aclList != null) {
                 aclDataUtil.addAclInterfaceMap(aclList, aclInterface);
index 2cf363a356bd25e11a02041c0029f660477da72c..42cad9555368adc0d5918b8f430de707ff5125e8 100644 (file)
@@ -159,12 +159,8 @@ public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapable
                 securityGroupMode == null ? SecurityGroupMode.Stateful : securityGroupMode);
 
         if (securityGroupMode == null || securityGroupMode == SecurityGroupMode.Stateful) {
-            addStatefulIngressAclTableMissFlow(dpnId);
-            addStatefulEgressAclTableMissFlow(dpnId);
-            addConntrackRules(dpnId, NwConstants.LPORT_DISPATCHER_TABLE, NwConstants.INGRESS_ACL_FILTER_TABLE,
-                    NwConstants.ADD_FLOW);
-            addConntrackRules(dpnId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, NwConstants.EGRESS_ACL_FILTER_TABLE,
-                    NwConstants.ADD_FLOW);
+            addStatefulIngressDefaultFlows(dpnId);
+            addStatefulEgressDefaultFlows(dpnId);
             addConntrackDummyLookup(dpnId, NwConstants.ADD_FLOW);
         } else if (securityGroupMode == SecurityGroupMode.Transparent) {
             addTransparentIngressAclTableMissFlow(dpnId);
@@ -180,6 +176,13 @@ public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapable
         }
     }
 
+    private void addStatefulEgressDefaultFlows(BigInteger dpId) {
+        addStatefulEgressAclTableMissFlow(dpId);
+        addConntrackRules(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, NwConstants.EGRESS_ACL_FILTER_TABLE,
+                NwConstants.ADD_FLOW);
+        addStatefulEgressDropFlows(dpId);
+    }
+
     /**
      * Adds the egress acl table miss flow.
      *
@@ -256,6 +259,36 @@ public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapable
         LOG.debug("Added Egress ACL Filter Table allow all Flows for dpn {}", dpId);
     }
 
+    private void addStatefulEgressDropFlows(BigInteger dpId) {
+        List<InstructionInfo> dropInstructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
+        List<MatchInfoBase> arpDropMatches = new ArrayList<>();
+        arpDropMatches.add(MatchEthernetType.ARP);
+        FlowEntity antiSpoofingArpDropFlowEntity =
+                MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
+                        "Egress ACL Table ARP Drop Flow", AclConstants.PROTO_ARP_TRAFFIC_DROP_PRIORITY,
+                        "Egress ACL Table ARP Drop Flow", 0, 0, AclConstants.COOKIE_ACL_BASE, arpDropMatches,
+                        dropInstructions);
+        mdsalManager.installFlow(antiSpoofingArpDropFlowEntity);
+
+        List<MatchInfoBase> ipDropMatches = new ArrayList<>();
+        ipDropMatches.add(MatchEthernetType.IPV4);
+        FlowEntity antiSpoofingIpDropFlowEntity =
+                MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
+                        "Egress ACL Table IP Drop Flow", AclConstants.PROTO_IP_TRAFFIC_DROP_PRIORITY,
+                        "Egress ACL Table IP Drop Flow", 0, 0, AclConstants.COOKIE_ACL_BASE, ipDropMatches,
+                        dropInstructions);
+        mdsalManager.installFlow(antiSpoofingIpDropFlowEntity);
+
+        List<MatchInfoBase> ipv6DropMatches = new ArrayList<>();
+        ipv6DropMatches.add(MatchEthernetType.IPV6);
+        FlowEntity antiSpoofingIpv6DropFlowEntity =
+                MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
+                        "Egress ACL Table IPv6 Drop Flow", AclConstants.PROTO_IP_TRAFFIC_DROP_PRIORITY,
+                        "Egress ACL Table IPv6 Drop Flow", 0, 0, AclConstants.COOKIE_ACL_BASE, ipv6DropMatches,
+                        dropInstructions);
+        mdsalManager.installFlow(antiSpoofingIpv6DropFlowEntity);
+    }
+
     private void addLearnEgressAclTableMissFlow(BigInteger dpId) {
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
@@ -545,6 +578,13 @@ public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapable
         LOG.debug("Added Stateless Egress ACL Table Miss Flows for dpn {}", dpId);
     }
 
+    private void addStatefulIngressDefaultFlows(BigInteger dpId) {
+        addStatefulIngressAclTableMissFlow(dpId);
+        addConntrackRules(dpId, NwConstants.LPORT_DISPATCHER_TABLE, NwConstants.INGRESS_ACL_FILTER_TABLE,
+                NwConstants.ADD_FLOW);
+        addStatefulIngressAllowBroadcastFlow(dpId);
+    }
+
     /**
      * Adds the ingress acl table miss flow.
      *
@@ -591,6 +631,28 @@ public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapable
         LOG.debug("Added Ingress ACL Remote Table Miss Flows for dpn {}", dpId);
     }
 
+    private void addStatefulIngressAllowBroadcastFlow(BigInteger dpId) {
+        final List<MatchInfoBase> ipBroadcastMatches =
+                AclServiceUtils.buildBroadcastIpV4Matches(AclConstants.IPV4_ALL_SUBNET_BROADCAST_ADDR);
+        List<InstructionInfo> ipBroadcastInstructions = new ArrayList<>();
+        ipBroadcastInstructions.add(new InstructionGotoTable(NwConstants.EGRESS_ACL_REMOTE_ACL_TABLE));
+        String ipBroadcastflowName = "Ingress_v4_Broadcast_" + dpId + "_Permit";
+        FlowEntity ipBroadcastFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
+                ipBroadcastflowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE,
+                ipBroadcastMatches, ipBroadcastInstructions);
+        mdsalManager.installFlow(ipBroadcastFlowEntity);
+
+        final List<MatchInfoBase> l2BroadcastMatch = AclServiceUtils.buildL2BroadcastMatches();
+        List<ActionInfo> l2BroadcastActionsInfos = new ArrayList<>();
+        List<InstructionInfo> l2BroadcastInstructions = getDispatcherTableResubmitInstructions(l2BroadcastActionsInfos,
+                NwConstants.EGRESS_LPORT_DISPATCHER_TABLE);
+        String l2BroadcastflowName = "Ingress_L2_Broadcast_" + dpId + "_Permit";
+        FlowEntity l2BroadcastFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
+                l2BroadcastflowName, AclConstants.PROTO_L2BROADCAST_TRAFFIC_MATCH_PRIORITY, "ACL", 0, 0,
+                AclConstants.COOKIE_ACL_BASE, l2BroadcastMatch, l2BroadcastInstructions);
+        mdsalManager.installFlow(l2BroadcastFlowEntity);
+    }
+
     private void addConntrackRules(BigInteger dpnId, short dispatcherTableId,short tableId, int write) {
         programConntrackForwardRule(dpnId, AclConstants.CT_STATE_TRACKED_EXIST_PRIORITY,
             "Tracked_Established", AclConstants.TRACKED_EST_CT_STATE, AclConstants.TRACKED_EST_CT_STATE_MASK,
index 5445714e7dcaf77241f8bc7c60da5bf79f5472ab..3eb9280ed3e15c5ae1991f040790d791c7a580a1 100644 (file)
@@ -25,8 +25,10 @@ public final class AclConstants {
     public static final Integer PROTO_DHCP_SERVER_MATCH_PRIORITY = 63010;
     public static final Integer PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY = 63010;
     public static final Integer PROTO_ARP_TRAFFIC_MATCH_PRIORITY = 63010;
+    public static final Integer PROTO_ARP_TRAFFIC_DROP_PRIORITY = 63009;
+    public static final Integer PROTO_L2BROADCAST_TRAFFIC_MATCH_PRIORITY = 61005;
     public static final Integer PROTO_MATCH_PRIORITY = 61010;
-    public static final Integer PREFIX_MATCH_PRIORITY = 61009;
+    public static final Integer PROTO_IP_TRAFFIC_DROP_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;
@@ -61,6 +63,9 @@ public final class AclConstants {
 
     public static final String IPV4_ALL_NETWORK = "0.0.0.0/0";
     public static final String IPV6_ALL_NETWORK = "::/0";
+    public static final String BROADCAST_MAC = "ff:ff:ff:ff:ff:ff";
+    public static final String IPV4_ALL_SUBNET_BROADCAST_ADDR = "255.255.255.255";
+
     public static final long TCP_FLAG_SYN = 1 << 1;
     public static final long TCP_FLAG_ACK = 1 << 4;
     public static final long TCP_FLAG_SYN_ACK = TCP_FLAG_SYN + TCP_FLAG_ACK;
index 93cfc120aac5ca2a2a45328f0ac40a90de0eaedd..fac2529937e7b8cf9cf9d25b53c7bb3775b247db 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.netvirt.aclservice.utils;
 
 import com.google.common.base.Optional;
+import com.google.common.net.InetAddresses;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -21,6 +22,7 @@ import javax.inject.Inject;
 import javax.inject.Singleton;
 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.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
@@ -30,6 +32,7 @@ import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
 import org.opendaylight.genius.mdsalutil.matches.MatchArpSpa;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
@@ -61,6 +64,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
@@ -92,8 +96,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeCon
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.PortsSubnetIpPrefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
@@ -170,6 +177,12 @@ public final class AclServiceUtils {
         }
     }
 
+    public static <T extends DataObject> void delete(
+            DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        tx.delete(datastoreType, path);
+    }
+
     /**
      * Retrieves the acl matching the key from the data store.
      *
@@ -354,6 +367,20 @@ public final class AclServiceUtils {
         return matches;
     }
 
+    public static List<MatchInfoBase> buildBroadcastIpV4Matches(String ipAddr) {
+        List<MatchInfoBase> matches = new ArrayList<>(2);
+        matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
+        matches.addAll(AclServiceUtils.buildIpMatches(new IpPrefixOrAddress(ipAddr.toCharArray()),
+                MatchCriteria.MATCH_DESTINATION));
+        return matches;
+    }
+
+    public static List<MatchInfoBase> buildL2BroadcastMatches() {
+        List<MatchInfoBase> matches = new ArrayList<>();
+        matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
+        return matches;
+    }
+
     /**
      * Builds the service id.
      *
@@ -455,6 +482,33 @@ public final class AclServiceUtils {
         return dpId;
     }
 
+    public static List<String> getIpBroadcastAddresses(List<IpPrefixOrAddress> cidrs) {
+        List<String> ipBroadcastAddresses = new ArrayList<>();
+        for (IpPrefixOrAddress cidr : cidrs) {
+            IpPrefix cidrIpPrefix = cidr.getIpPrefix();
+            if (cidrIpPrefix != null) {
+                Ipv4Prefix cidrIpv4Prefix = cidrIpPrefix.getIpv4Prefix();
+                if (cidrIpv4Prefix != null) {
+                    ipBroadcastAddresses.add(getBroadcastAddressFromCidr(cidrIpv4Prefix.getValue()));
+                }
+            }
+        }
+        return ipBroadcastAddresses;
+    }
+
+    public static String getBroadcastAddressFromCidr(String cidr) {
+        String[] ipaddressValues = cidr.split("/");
+        int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
+        int cidrPart = Integer.parseInt(ipaddressValues[1]);
+        int netmask = 0;
+        for (int j = 0; j < cidrPart; ++j) {
+            netmask |= (1 << 31 - j);
+        }
+        int network = (address & netmask);
+        int broadcast = network | ~(netmask);
+        return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));
+    }
+
     /**
      * Builds the ip matches.
      *
@@ -734,6 +788,22 @@ public final class AclServiceUtils {
                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
     }
 
+    public static List<IpPrefixOrAddress> getSubnetIpPrefixes(DataBroker broker, String portId) {
+        InstanceIdentifier<PortSubnetIpPrefixes> id = InstanceIdentifier.builder(PortsSubnetIpPrefixes.class)
+                .child(PortSubnetIpPrefixes.class, new PortSubnetIpPrefixesKey(portId)).build();
+        Optional<PortSubnetIpPrefixes> portSubnetIpPrefixes = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (portSubnetIpPrefixes.isPresent()) {
+            return portSubnetIpPrefixes.get().getSubnetIpPrefixes();
+        }
+        return null;
+    }
+
+    public static void deleteSubnetIpPrefixes(DataBroker broker, String portId) {
+        InstanceIdentifier<PortSubnetIpPrefixes> id = InstanceIdentifier.builder(PortsSubnetIpPrefixes.class)
+                    .child(PortSubnetIpPrefixes.class, new PortSubnetIpPrefixesKey(portId)).build();
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
     public static Long getVpnIdFromInterface(DataBroker broker, String vpnInterfaceName) {
         VpnInterface vpnInterface = VpnHelper.getVpnInterface(broker, vpnInterfaceName);
         if (vpnInterface != null) {
index ec1f65521cc97604cd792e6e420a9343d5a8f679..ae3304cbeb5feec837a8fb73bdb2d2486e94027a 100644 (file)
@@ -157,9 +157,30 @@ class FlowEntryObjectsBase {
             ]
     }
 
-     protected def fixedEgressFlowsPort1() {
+     protected def fixedEgressL2BroadcastFlowsPort1() {
         #[
+            new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_0D:AA:D8:42:30:F3"
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress("0D:AA:D8:42:30:F3")),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
+            ]
+        ]
+     }
 
+     protected def fixedEgressFlowsPort1() {
+        #[
             new FlowEntityBuilder >> [
                 dpnId = 123bi
                 cookie = 110100480bi
@@ -457,6 +478,28 @@ class FlowEntryObjectsBase {
         ]
     }
 
+     protected def fixedEgressL2BroadcastFlowsPort2 () {
+        #[
+            new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_0D:AA:D8:42:30:F4"
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress("0D:AA:D8:42:30:F4")),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
+            ]
+         ]
+     }
+
      protected def fixedEgressFlowsPort2 () {
         #[
             new FlowEntityBuilder >> [
@@ -755,6 +798,28 @@ class FlowEntryObjectsBase {
         ]
     }
 
+    protected def fixedEgressL2BroadcastFlowsPort3 () {
+       #[
+           new FlowEntityBuilder >> [
+               dpnId = 123bi
+               cookie = 110100480bi
+               flowId = "Egress_L2Broadcast_123_987_0D:AA:D8:42:30:F5"
+               flowName = "ACL"
+               instructionInfoList = #[
+                   new InstructionApplyActions(#[
+                       new ActionNxResubmit(17 as short)
+                   ])
+               ]
+               matchInfoList = #[
+                   new MatchEthernetSource(new MacAddress("0D:AA:D8:42:30:F5")),
+                   new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+               ]
+               priority = 61005
+               tableId = 211 as short
+           ]
+        ]
+    }
+
      protected def fixedEgressFlowsPort3 () {
         #[
             new FlowEntityBuilder >> [
index 00e57c65a9e09f77b2bdcd1ca2f10625430e3747..86c98b1e872c5a8a921ac26c16709f183e10887a 100644 (file)
@@ -47,6 +47,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
     protected def etherFlows() {
         fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + etherEgressFlowsPort1
@@ -54,6 +55,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         + fixedConntrackIngressFlowsPort2
         + etherIngressFlowsPort2
         + etherIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + fixedConntrackEgressFlowsPort2
         + etheregressFlowPort2
@@ -64,11 +66,13 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
         + tcpIngressFlowPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + fixedIngressFlowsPort2
         + fixedConntrackIngressFlowsPort2
         + tcpIngressFlowPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + fixedConntrackEgressFlowsPort2
         + tcpEgressFlowPort2
@@ -79,6 +83,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
     protected def udpFlows() {
         fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + udpEgressFlowsPort1
@@ -86,6 +91,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         + fixedConntrackIngressFlowsPort2
         + udpIngressFlowsPort2
         + udpIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + fixedConntrackEgressFlowsPort2
         + udpEgressFlowsPort2
@@ -96,11 +102,13 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
         + icmpIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + fixedIngressFlowsPort2
         + fixedConntrackIngressFlowsPort2
         + icmpIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + fixedConntrackEgressFlowsPort2
         + icmpEgressFlowsPort2
@@ -112,6 +120,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         fixedIngressFlowsPort1
         +fixedConntrackIngressFlowsPort1
         + udpIngressPortRangeFlows
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + tcpEgressRangeFlows
@@ -121,6 +130,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
         + udpIngressAllFlows
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + tcpEgressAllFlows
@@ -149,6 +159,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
     protected def multipleAcl() {
           fixedIngressFlowsPort1
         + fixedConntrackIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedConntrackEgressFlowsPort1
         + etherEgressFlowsPort1
@@ -158,6 +169,7 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
         + fixedConntrackIngressFlowsPort2
         + etherIngressFlowsPort2
         + etherIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + fixedConntrackEgressFlowsPort2
         + etheregressFlowPort2
@@ -373,6 +385,23 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
                 ]
                 priority = 63010
                 tableId = NwConstants.INGRESS_ACL_TABLE
+            ],
+            new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_0D:AA:D8:42:30:A4"
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress("0D:AA:D8:42:30:A4")),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
             ]
          ]
     }
@@ -544,6 +573,23 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
                 ]
                 priority = 63010
                 tableId = 211 as short
+            ],
+            new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_0D:AA:D8:42:30:A4"
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress("0D:AA:D8:42:30:A4")),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
             ]
         ]
     }
@@ -2141,6 +2187,23 @@ class FlowEntryObjectsStateful extends FlowEntryObjectsBase {
                 ]
                 priority = 63010
                 tableId = 211 as short
+            ],
+            new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_" + mac
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress(mac)),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
             ]
         ]
     }
index 6c4801e88aa9352d67d890494da59ba65e90bae5..d1d99f4c8b5dbda77a0643292ecf05f45b71bec4 100644 (file)
@@ -41,10 +41,12 @@ class FlowEntryObjectsStateless extends FlowEntryObjectsBase {
     protected def etherFlows() {
         fixedIngressFlowsPort1
         + etherFlowIngressPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + etherFlowEgressPort1
         + fixedIngressFlowsPort2
         + etherIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + etheregressFlowPort2
         + remoteFlows
@@ -53,10 +55,12 @@ class FlowEntryObjectsStateless extends FlowEntryObjectsBase {
     protected def tcpFlows() {
         fixedIngressFlowsPort1
         + tcpIngressFlowPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + tcpEgressFlowPort1
         + fixedIngressFlowsPort2
         + tcpIngressFlowPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + tcpEgressFlowPort2
         + remoteFlows
@@ -64,33 +68,40 @@ class FlowEntryObjectsStateless extends FlowEntryObjectsBase {
 
     protected def udpFlows() {
         fixedIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + remoteFlows
     }
 
     protected def icmpFlows() {
         fixedIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + fixedIngressFlowsPort2
+        + fixedEgressL2BroadcastFlowsPort2
         + fixedEgressFlowsPort2
         + remoteFlows
     }
 
     protected def dstRangeFlows() {
         fixedIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
         + tcpEgressRangeFlows
     }
 
     protected def dstAllFlows() {
         fixedIngressFlowsPort1
+        + fixedEgressL2BroadcastFlowsPort1
         + fixedEgressFlowsPort1
     }
 
     protected def icmpFlowsForTwoAclsHavingSameRules() {
         fixedIngressFlowsPort3
+        + fixedEgressL2BroadcastFlowsPort3
         + fixedEgressFlowsPort3
     }
 
@@ -1121,6 +1132,23 @@ class FlowEntryObjectsStateless extends FlowEntryObjectsBase {
                 ]
                 priority = 63010
                 tableId = 211 as short
+            ],
+             new FlowEntityBuilder >> [
+                dpnId = 123bi
+                cookie = 110100480bi
+                flowId = "Egress_L2Broadcast_123_987_" + mac
+                flowName = "ACL"
+                instructionInfoList = #[
+                    new InstructionApplyActions(#[
+                        new ActionNxResubmit(17 as short)
+                    ])
+                ]
+                matchInfoList = #[
+                    new MatchEthernetSource(new MacAddress(mac)),
+                    new MatchMetadata(1085217976614912bi, MetaDataUtil.METADATA_MASK_LPORT_TAG)
+                ]
+                priority = 61005
+                tableId = 211 as short
             ]
         ]
     }
index f7ba82fae956b23d873bc0e1cf073f6cba2b05b3..df9d60f246212a7578b0261c8c39e9ee883d7d89 100644 (file)
@@ -217,7 +217,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
                     if (optionalInf.isPresent()) {
                         InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
                         if (origSecurityEnabled || updatedSecurityEnabled) {
-                            InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
+                            InterfaceAcl infAcl = handlePortSecurityUpdated(dataBroker, original, update,
                                     origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
                             interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
                         }
@@ -464,8 +464,9 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
         });
     }
 
-    private static InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal, Port portUpdated, boolean
-            origSecurityEnabled, boolean updatedSecurityEnabled, InterfaceBuilder interfaceBuilder) {
+    private static InterfaceAclBuilder handlePortSecurityUpdated(DataBroker dataBroker, Port portOriginal,
+            Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
+            InterfaceBuilder interfaceBuilder) {
         String interfaceName = portUpdated.getUuid().getValue();
         InterfaceAclBuilder interfaceAclBuilder = null;
         if (origSecurityEnabled != updatedSecurityEnabled) {
@@ -535,6 +536,7 @@ public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<P
             interfaceAclBuilder.setPortSecurityEnabled(true);
             NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
             interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
+            NeutronvpnUtils.populateSubnetIpPrefixes(dataBroker, port);
         }
         return interfaceBuilder.build();
     }
index f015eeeb764af1bdba7ab32dbfec3153ba222096..3107f35a7579e23eeabca0410aed5005c7401453 100644 (file)
@@ -57,8 +57,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.PortsSubnetIpPrefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeGre;
@@ -672,6 +676,37 @@ public class NeutronvpnUtils {
         interfaceAclBuilder.setAllowedAddressPairs(aclAllowedAddressPairs);
     }
 
+    protected static void populateSubnetIpPrefixes(DataBroker broker, Port port) {
+        List<IpPrefixOrAddress> subnetIpPrefixes = NeutronvpnUtils.getSubnetIpPrefixes(broker, port);
+        if (subnetIpPrefixes != null) {
+            String portId = port.getUuid().getValue();
+            InstanceIdentifier portSubnetIpPrefixIdentifier =
+                NeutronvpnUtils.buildPortSubnetIpPrefixIdentifier(portId);
+            PortSubnetIpPrefixesBuilder subnetIpPrefixesBuilder = new PortSubnetIpPrefixesBuilder()
+                    .setKey(new PortSubnetIpPrefixesKey(portId)).setPortId(portId)
+                    .setSubnetIpPrefixes(subnetIpPrefixes);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portSubnetIpPrefixIdentifier,
+                    subnetIpPrefixesBuilder.build());
+            LOG.debug("Created Subnet IP Prefixes for port {}", port.getUuid().getValue());
+        }
+    }
+
+    protected static List<IpPrefixOrAddress> getSubnetIpPrefixes(DataBroker broker, Port port) {
+        List<Uuid> subnetIds = getSubnetIdsFromNetworkId(broker, port.getNetworkId());
+        if (subnetIds == null) {
+            LOG.error("Failed to get Subnet Ids for the Network {}", port.getNetworkId());
+            return null;
+        }
+        List<IpPrefixOrAddress> subnetIpPrefixes = new ArrayList<>();
+        for (Uuid subnetId : subnetIds) {
+            Subnet subnet = getNeutronSubnet(broker, subnetId);
+            if (subnet != null) {
+                subnetIpPrefixes.add(new IpPrefixOrAddress(subnet.getCidr()));
+            }
+        }
+        return subnetIpPrefixes;
+    }
+
     protected static Subnet getNeutronSubnet(DataBroker broker, Uuid subnetId) {
         Subnet subnet = null;
         subnet = subnetMap.get(subnetId);
@@ -1018,6 +1053,12 @@ public class NeutronvpnUtils {
                 FloatingIpIdToPortMappingKey(floatingIpId)).build();
     }
 
+    static InstanceIdentifier<PortSubnetIpPrefixes> buildPortSubnetIpPrefixIdentifier(String portId) {
+        InstanceIdentifier<PortSubnetIpPrefixes> id = InstanceIdentifier.builder(PortsSubnetIpPrefixes.class)
+            .child(PortSubnetIpPrefixes.class, new PortSubnetIpPrefixesKey(portId)).build();
+        return id;
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,