Bug 7775: Updated to use DataStoreJobCoordinator for flow programming
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractEgressAclServiceImpl.java
index fade9b3e04e857f12ff20531d34dfc269d9a6171..f9234692c8ef4d0adbe87ca08b59ecef9ee6d06c 100644 (file)
@@ -7,25 +7,31 @@
  */
 package org.opendaylight.netvirt.aclservice;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
-import org.opendaylight.genius.mdsalutil.ActionType;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpSha;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
+import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
@@ -34,6 +40,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.AceType;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
+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.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
@@ -61,10 +68,15 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
      *
      * @param dataBroker the data broker instance.
      * @param mdsalManager the mdsal manager instance.
+     * @param aclDataUtil
+     *            the acl data util.
+     * @param aclServiceUtils
+     *            the acl service util.
      */
-    public AbstractEgressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager) {
+    public AbstractEgressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
+            AclServiceUtils aclServiceUtils) {
         // Service mode is w.rt. switch
-        super(ServiceModeIngress.class, dataBroker, mdsalManager);
+        super(ServiceModeIngress.class, dataBroker, mdsalManager, aclDataUtil, aclServiceUtils);
     }
 
     /**
@@ -78,14 +90,27 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
 
         int instructionKey = 0;
         List<Instruction> instructions = new ArrayList<>();
+        Long elanTag = AclServiceUtils.getElanIdFromInterface(interfaceName, dataBroker);
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getElanTagMetadata(elanTag),
+                MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.INGRESS_ACL_TABLE, ++instructionKey));
         short serviceIndex = ServiceIndex.getIndex(NwConstants.ACL_SERVICE_NAME, NwConstants.ACL_SERVICE_INDEX);
         BoundServices serviceInfo =
-                AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "vpn", "egressacl", interfaceName),
+                AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "acl", "egressacl", interfaceName),
                 serviceIndex, flowPriority, AclConstants.COOKIE_ACL_BASE, instructions);
         InstanceIdentifier<BoundServices> path =
                 AclServiceUtils.buildServiceId(interfaceName, serviceIndex, ServiceModeIngress.class);
-        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, serviceInfo);
+
+        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+        dataStoreCoordinator.enqueueJob(interfaceName,
+            () -> {
+                WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+                writeTxn.put(LogicalDatastoreType.CONFIGURATION, path, serviceInfo, true);
+
+                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                futures.add(writeTxn.submit());
+                return futures;
+            });
     }
 
     /**
@@ -99,7 +124,17 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
                 AclServiceUtils.buildServiceId(interfaceName,
                         ServiceIndex.getIndex(NwConstants.ACL_SERVICE_NAME, NwConstants.ACL_SERVICE_INDEX),
                         ServiceModeIngress.class);
-        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
+
+        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+        dataStoreCoordinator.enqueueJob(interfaceName,
+            () -> {
+                WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+                writeTxn.delete(LogicalDatastoreType.CONFIGURATION, path);
+
+                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                futures.add(writeTxn.submit());
+                return futures;
+            });
     }
 
     @Override
@@ -112,8 +147,8 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
             egressAclDhcpv6AllowClientTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove);
             egressAclDhcpDropServerTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove);
             egressAclDhcpv6DropServerTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove);
-            egressAclIcmpv6AllowAll(dpid, lportTag, addOrRemove);
             egressAclIcmpv6DropRouterAdvts(dpid, lportTag, addOrRemove);
+            egressAclIcmpv6AllowedList(dpid, lportTag, addOrRemove);
         }
         programArpRule(dpid, allowedAddresses, lportTag, addOrRemove);
     }
@@ -122,7 +157,12 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
     protected boolean programAclRules(List<Uuid> aclUuidList, BigInteger dpId, int lportTag, int addOrRemove, String
             portId) {
         LOG.trace("Applying custom rules DpId {}, lportTag {}", dpId, lportTag);
-        for (Uuid sgUuid :aclUuidList ) {
+        if (aclUuidList == null || dpId == null) {
+            LOG.warn("one of the egress acl parameters can not be null. sg {}, dpId {}",
+                    aclUuidList, dpId);
+            return false;
+        }
+        for (Uuid sgUuid :aclUuidList) {
             Acl acl = AclServiceUtils.getAcl(dataBroker, sgUuid.getValue());
             if (null == acl) {
                 LOG.warn("The ACL is empty");
@@ -131,15 +171,15 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
             AccessListEntries accessListEntries = acl.getAccessListEntries();
             List<Ace> aceList = accessListEntries.getAce();
             for (Ace ace: aceList) {
-                programAceRule(dpId, lportTag, addOrRemove, ace, portId, null);
+                programAceRule(dpId, lportTag, addOrRemove, acl.getAclName(), ace, portId, null);
             }
         }
         return true;
     }
 
     @Override
-    protected void programAceRule(BigInteger dpId, int lportTag, int addOrRemove, Ace ace, String portId,
-                                  List<AllowedAddressPairs> syncAllowedAddresses) {
+    protected void programAceRule(BigInteger dpId, int lportTag, int addOrRemove, String aclName, Ace ace,
+            String portId, List<AllowedAddressPairs> syncAllowedAddresses) {
         SecurityRuleAttr aceAttr = AclServiceUtils.getAccesssListAttributes(ace);
         if (!aceAttr.getDirection().equals(DirectionEgress.class)) {
             return;
@@ -152,17 +192,15 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
             if (syncAllowedAddresses != null) {
                 flowMap = AclServiceUtils.getFlowForAllowedAddresses(syncAllowedAddresses, flowMap, false);
             } else if (aceAttr.getRemoteGroupId() != null) {
-                flowMap = AclServiceUtils.getFlowForRemoteAcl(aceAttr.getRemoteGroupId(), portId, flowMap,
-                    false);
+                flowMap = aclServiceUtils.getFlowForRemoteAcl(aceAttr.getRemoteGroupId(), portId, flowMap, false);
             }
         }
         if (null == flowMap) {
             LOG.error("Failed to apply ACL {} lportTag {}", ace.getKey(), lportTag);
             return;
         }
-        //The flow map contains list of flows if port range is selected.
-        for ( String  flowName : flowMap.keySet()) {
-            flowName = syncSpecificAclFlow(dpId, lportTag, addOrRemove, ace, portId, flowMap, flowName);
+        for (String flowName : flowMap.keySet()) {
+            syncSpecificAclFlow(dpId, lportTag, addOrRemove, ace, portId, flowMap, flowName);
         }
     }
 
@@ -184,7 +222,7 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
+        actionsInfos.add(new ActionDrop());
         String flowName = "Egress_DHCP_Server_v4" + dpId + "_" + lportTag + "_" + dhcpMacAddress + "_Drop_";
         syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName,
                 AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY, "ACL", 0,
@@ -206,7 +244,7 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
+        actionsInfos.add(new ActionDrop());
         String flowName = "Egress_DHCP_Server_v6" + "_" + dpId + "_" + lportTag + "_" + dhcpMacAddress + "_Drop_";
         syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName,
                 AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY, "ACL", 0,
@@ -214,39 +252,40 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
     }
 
     /**
-     * Add rule to allow all ICMPv6 traffic from the VM port.
+     * Anti-spoofing rule to block the Ipv6 Router Advts from the VM port.
      *
      * @param dpId the dpId
      * @param lportTag the lport tag
      * @param addOrRemove add/remove the flow.
      */
-    private void egressAclIcmpv6AllowAll(BigInteger dpId, int lportTag, int addOrRemove) {
-        final List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(0, 0, lportTag);
+    private void egressAclIcmpv6DropRouterAdvts(BigInteger dpId, int lportTag, int addOrRemove) {
+        List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0, lportTag);
 
+        List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
-
-        String flowName = "Egress_ICMPv6_ALL" + dpId + "_" + lportTag + "_Permit_";
-        syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY,
-                "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        actionsInfos.add(new ActionDrop());
+        String flowName = "Egress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_RA + "_Drop_";
+        syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName, AclConstants.PROTO_IPV6_DROP_PRIORITY, "ACL", 0,
+                0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
     }
 
     /**
-     * Anti-spoofing rule to block the Ipv6 Router Advts from the VM port.
+     * Add rule to allow certain ICMPv6 traffic from VM ports.
      *
      * @param dpId the dpId
      * @param lportTag the lport tag
      * @param addOrRemove add/remove the flow.
      */
-    private void egressAclIcmpv6DropRouterAdvts(BigInteger dpId, int lportTag, int addOrRemove) {
-        List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0, lportTag);
-
-        List<InstructionInfo> instructions = new ArrayList<>();
+    private void egressAclIcmpv6AllowedList(BigInteger dpId, int lportTag, int addOrRemove) {
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
-        String flowName = "Egress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_RA + "_Drop_";
-        syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName, AclConstants.PROTO_IPV6_DROP_PRIORITY, "ACL", 0,
-                0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
+
+        for (Integer icmpv6Type: AclConstants.allowedIcmpv6NdList()) {
+            List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(icmpv6Type, 0, lportTag);
+            String flowName = "Egress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + icmpv6Type + "_Permit_";
+            syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY,
+                    "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        }
     }
 
     /**
@@ -304,15 +343,15 @@ public abstract class AbstractEgressAclServiceImpl extends AbstractAclServiceImp
     protected void programArpRule(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses, int lportTag,
             int addOrRemove) {
         for (AllowedAddressPairs allowedAddress : allowedAddresses) {
-            String attachMac = allowedAddress.getMacAddress().getValue();
+            MacAddress attachMac = allowedAddress.getMacAddress();
             List<MatchInfo> matches = new ArrayList<>();
-            matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_ARP}));
-            matches.add(new MatchInfo(MatchFieldType.arp_sha, new String[] {attachMac}));
+            matches.add(MatchEthernetType.ARP);
+            matches.add(new MatchArpSha(attachMac));
             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag));
 
             List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(new ArrayList<>());
 
-            String flowName = "Egress_ARP_" + dpId + "_" + attachMac;
+            String flowName = "Egress_ARP_" + dpId + "_" + lportTag + "_" + attachMac.getValue();
             syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName,
                     AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, "ACL", 0, 0,
                     AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);