Merge "ACL: Enabling ACL service in the pipeline"
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractAclServiceImpl.java
index 760571fe7846bf6b11cfa972a591aec58707e7dc..f4c6e72cd3be390172541d10a51fe01ccf6766ec 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.netvirt.aclservice;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.ActionType;
@@ -21,12 +23,14 @@ import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.aclservice.api.AclServiceListener;
+import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
+import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
+import org.opendaylight.netvirt.aclservice.api.utils.AclInterfaceCacheUtil;
 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
+import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
 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.access.list.entries.Ace;
-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.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
@@ -37,56 +41,50 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(AbstractAclServiceImpl.class);
 
-    private final IMdsalApiManager mdsalManager;
-    private final OdlInterfaceRpcService interfaceManager;
-    private final DataBroker dataBroker;
-    private final Class<? extends ServiceModeBase> serviceMode;
+    protected final IMdsalApiManager mdsalManager;
+    protected final DataBroker dataBroker;
+    protected final Class<? extends ServiceModeBase> serviceMode;
 
     /**
      * Initialize the member variables.
      *
-     * @param serviceMode the service mode
-     * @param dataBroker the data broker instance.
-     * @param interfaceManager the interface manager instance.
-     * @param mdsalManager the mdsal manager instance.
+     * @param serviceMode
+     *            the service mode
+     * @param dataBroker
+     *            the data broker instance.
+     * @param mdsalManager
+     *            the mdsal manager instance.
      */
     public AbstractAclServiceImpl(Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker,
-            OdlInterfaceRpcService interfaceManager, IMdsalApiManager mdsalManager) {
+            IMdsalApiManager mdsalManager) {
         this.dataBroker = dataBroker;
-        this.interfaceManager = interfaceManager;
         this.mdsalManager = mdsalManager;
         this.serviceMode = serviceMode;
     }
 
     @Override
-    public boolean applyAcl(Interface port) {
-
-        if (!AclServiceUtils.isPortSecurityEnabled(port)) {
+    public boolean applyAcl(AclInterface port) {
+        if (port == null) {
+            LOG.error("port cannot be null");
             return false;
         }
-
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
-            interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
-        BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
-        if (dpId == null) {
-            LOG.error("Unable to find DP Id from interface state {}", interfaceState.getName());
+        BigInteger dpId = port.getDpId();
+        if (dpId == null || port.getLPortTag() == null) {
+            LOG.error("Unable to find DP Id from ACL interface with id {}", port.getInterfaceId());
             return false;
         }
+        programAclWithAllowedAddress(dpId, port.getAllowedAddressPairs(), port.getLPortTag(), port.getSecurityGroups(),
+                Action.ADD, NwConstants.ADD_FLOW, port.getInterfaceId());
 
-        programAclWithAllowedAddress(dpId, AclServiceUtils.getPortAllowedAddresses(port), interfaceState.getIfIndex(),
-                AclServiceUtils.getInterfaceAcls(port), NwConstants.ADD_FLOW);
-
-        // TODO: uncomment bindservice() when the acl flow programming is
-        // implemented
-        // bindService(port.getName());
+        bindService(port.getInterfaceId());
         return true;
     }
 
     @Override
-    public boolean updateAcl(Interface portBefore, Interface portAfter) {
+    public boolean updateAcl(AclInterface portBefore, AclInterface portAfter) {
         boolean result = false;
-        boolean isPortSecurityEnable = AclServiceUtils.isPortSecurityEnabled(portAfter);
-        boolean isPortSecurityEnableBefore = AclServiceUtils.isPortSecurityEnabled(portBefore);
+        boolean isPortSecurityEnable = portAfter.getPortSecurityEnabled();
+        boolean isPortSecurityEnableBefore = portBefore.getPortSecurityEnabled();
         // if port security is changed, apply/remove Acls
         if (isPortSecurityEnableBefore != isPortSecurityEnable) {
             if (isPortSecurityEnable) {
@@ -96,102 +94,128 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             }
         } else if (isPortSecurityEnable) {
             // Acls has been updated, find added/removed Acls and act accordingly.
-            this.processInterfaceUpdate(portBefore, portAfter);
+            processInterfaceUpdate(portBefore, portAfter);
         }
 
         return result;
     }
 
-    private void processInterfaceUpdate(Interface portBefore, Interface portAfter) {
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
-                interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, portAfter.getName());
-        BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
+    private void processInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
+        BigInteger dpId = portAfter.getDpId();
         List<AllowedAddressPairs> addedAllowedAddressPairs =
-                AclServiceUtils.getUpdatedAllowedAddressPairs(portAfter,portBefore);
+                AclServiceUtils.getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(),
+                        portBefore.getAllowedAddressPairs());
         List<AllowedAddressPairs> deletedAllowedAddressPairs =
-                AclServiceUtils.getUpdatedAllowedAddressPairs(portBefore, portAfter);
+                AclServiceUtils.getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(),
+                        portAfter.getAllowedAddressPairs());
         if (addedAllowedAddressPairs != null && !addedAllowedAddressPairs.isEmpty()) {
-            programAclWithAllowedAddress(dpId, addedAllowedAddressPairs, interfaceState.getIfIndex(),
-                    AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.ADD_FLOW);
+            programAclWithAllowedAddress(dpId, addedAllowedAddressPairs, portAfter.getLPortTag(),
+                    portAfter.getSecurityGroups(), Action.UPDATE, NwConstants.ADD_FLOW, portAfter.getInterfaceId());
         }
         if (deletedAllowedAddressPairs != null && !deletedAllowedAddressPairs.isEmpty()) {
-            programAclWithAllowedAddress(dpId, deletedAllowedAddressPairs, interfaceState.getIfIndex(),
-                    AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.DEL_FLOW);
+            programAclWithAllowedAddress(dpId, deletedAllowedAddressPairs, portAfter.getLPortTag(),
+                    portAfter.getSecurityGroups(), Action.UPDATE, NwConstants.DEL_FLOW, portAfter.getInterfaceId());
         }
 
-        List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter, portBefore);
-        List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore, portAfter);
+        List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter.getSecurityGroups(),
+                portBefore.getSecurityGroups());
+        List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore.getSecurityGroups(),
+                portAfter.getSecurityGroups());
         if (addedAcls != null && !addedAcls.isEmpty()) {
-            updateCustomRules(dpId, interfaceState.getIfIndex(), addedAcls, NwConstants.ADD_FLOW);
+            updateCustomRules(dpId, portAfter.getLPortTag(), addedAcls, NwConstants.ADD_FLOW,
+                    portAfter.getInterfaceId(), portAfter.getAllowedAddressPairs());
         }
         if (deletedAcls != null && !deletedAcls.isEmpty()) {
-            updateCustomRules(dpId, interfaceState.getIfIndex(), deletedAcls, NwConstants.DEL_FLOW);
+            updateCustomRules(dpId, portAfter.getLPortTag(), deletedAcls, NwConstants.DEL_FLOW,
+                    portAfter.getInterfaceId(), portAfter.getAllowedAddressPairs());
         }
     }
 
-    private void updateCustomRules(BigInteger dpId, int lportTag, List<Uuid> aclUuidList, int action) {
-        programAclRules(aclUuidList, dpId, lportTag, action);
+    private void updateCustomRules(BigInteger dpId, int lportTag, List<Uuid> aclUuidList, int action,
+                                   String portId, List<AllowedAddressPairs> syncAllowedAddresses) {
+        programAclRules(aclUuidList, dpId, lportTag, action, portId);
+        syncRemoteAclRules(aclUuidList, action, portId, syncAllowedAddresses);
+    }
+
+    private void syncRemoteAclRules(List<Uuid> aclUuidList, int action, String currentPortId,
+                                    List<AllowedAddressPairs> syncAllowedAddresses) {
+        for (Uuid remoteAclId : aclUuidList) {
+            Set<String> portSet = AclDataUtil.getRemoteAclInterfaces(remoteAclId);
+            if (portSet == null) {
+                continue;
+            }
+            for (String remotePortId : portSet) {
+                AclInterface port = AclInterfaceCacheUtil.getAclInterfaceFromCache(remotePortId);
+                if (currentPortId.equals(port.getInterfaceId())) {
+                    continue;
+                }
+                List<Ace> remoteAceList = AclServiceUtils.getAceWithRemoteAclId(dataBroker, port, remoteAclId);
+                for (Ace ace : remoteAceList) {
+                    programAceRule(port.getDpId(), port.getLPortTag(), action, ace, port.getInterfaceId(),
+                            syncAllowedAddresses);
+                }
+            }
+        }
     }
 
     private void programAclWithAllowedAddress(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses,
-            int lportTag, List<Uuid> aclUuidList, int addOrRemove) {
-        programFixedRules(dpId, "", allowedAddresses, lportTag, addOrRemove);
-        programAclRules(aclUuidList, dpId, lportTag, addOrRemove);
+                                              int lportTag, List<Uuid> aclUuidList, Action action, int addOrRemove,
+                                              String portId) {
+        programFixedRules(dpId, "", allowedAddresses, lportTag, action, addOrRemove);
+        if (action == Action.ADD || action == Action.REMOVE) {
+            programAclRules(aclUuidList, dpId, lportTag, addOrRemove, portId);
+        }
+        syncRemoteAclRules(aclUuidList, addOrRemove, portId, allowedAddresses);
     }
 
+
     @Override
-    public boolean removeAcl(Interface port) {
-        if (!AclServiceUtils.isPortSecurityEnabled(port)) {
+    public boolean removeAcl(AclInterface port) {
+        BigInteger dpId = port.getDpId();
+        if (dpId == null) {
+            LOG.error("Unable to find DP Id from ACL interface with id {}", port.getInterfaceId());
             return false;
         }
-        BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
-            interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
-        programAclWithAllowedAddress(dpId, AclServiceUtils.getPortAllowedAddresses(port), interfaceState.getIfIndex(),
-                AclServiceUtils.getInterfaceAcls(port), NwConstants.DEL_FLOW);
+        programAclWithAllowedAddress(dpId, port.getAllowedAddressPairs(), port.getLPortTag(), port.getSecurityGroups(),
+                Action.REMOVE, NwConstants.DEL_FLOW, port.getInterfaceId());
 
-        // TODO: uncomment unbindService() when the acl flow programming is
-        // implemented
-        // unbindService(port.getName());
+        unbindService(port.getInterfaceId());
         return true;
     }
 
     @Override
-    public boolean applyAce(Interface port, Ace ace) {
-        if (!AclServiceUtils.isPortSecurityEnabled(port)) {
+    public boolean applyAce(AclInterface port, Ace ace) {
+        if (!port.isPortSecurityEnabled()) {
             return false;
         }
-        BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
-                interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
-        programAceRule(dpId, interfaceState.getIfIndex(), NwConstants.ADD_FLOW, ace);
+        programAceRule(port.getDpId(), port.getLPortTag(), NwConstants.ADD_FLOW, ace,
+                port.getInterfaceId(), null);
         return true;
     }
 
     @Override
-    public boolean removeAce(Interface port, Ace ace) {
-        if (!AclServiceUtils.isPortSecurityEnabled(port)) {
+    public boolean removeAce(AclInterface port, Ace ace) {
+        if (!port.isPortSecurityEnabled()) {
             return false;
         }
-        BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
-                interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
-        programAceRule(dpId, interfaceState.getIfIndex(), NwConstants.DEL_FLOW, ace);
+        programAceRule(port.getDpId(), port.getLPortTag(), NwConstants.DEL_FLOW, ace,
+                port.getInterfaceId(), null);
         return true;
     }
 
-
     /**
      * Bind service.
      *
-     * @param interfaceName the interface name
+     * @param interfaceName
+     *            the interface name
      */
     protected abstract void bindService(String interfaceName);
 
     /**
      * Unbind service.
      *
-     * @param interfaceName the interface name
+     * @param interfaceName
+     *            the interface name
      */
     protected abstract void unbindService(String interfaceName);
 
@@ -202,10 +226,11 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      * @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 programFixedRules(BigInteger dpid, String dhcpMacAddress,
-            List<AllowedAddressPairs> allowedAddresses, int lportTag, int addOrRemove);
+            List<AllowedAddressPairs> allowedAddresses, int lportTag, Action action, int addOrRemove);
 
     /**
      * Programs the acl custom rules.
@@ -215,7 +240,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      * @param lportTag the lport tag
      * @param addOrRemove whether to delete or add flow
      */
-    protected abstract void programAclRules(List<Uuid> aclUuidList, BigInteger dpId, int lportTag, int addOrRemove);
+    protected abstract boolean programAclRules(List<Uuid> aclUuidList, BigInteger dpId, int lportTag, int addOrRemove,
+                                            String portId);
 
     /**
      * Programs the ace custom rule.
@@ -225,33 +251,46 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      * @param addOrRemove whether to delete or add flow
      * @param ace rule to be program
      */
-    protected abstract void programAceRule(BigInteger dpId, int lportTag, int addOrRemove, Ace ace);
+    protected abstract void programAceRule(BigInteger dpId, int lportTag, int addOrRemove, Ace ace, String portId,
+                                           List<AllowedAddressPairs> syncAllowedAddresses);
 
     /**
      * Writes/remove the flow to/from the datastore.
-     * @param dpId the dpId
-     * @param tableId the tableId
-     * @param flowId the flowId
-     * @param priority the priority
-     * @param flowName the flow name
-     * @param idleTimeOut the idle timeout
-     * @param hardTimeOut the hard timeout
-     * @param cookie the cookie
-     * @param matches the list of matches to be writted
-     * @param instructions the list of instruction to be written.
-     * @param addOrRemove add or remove the entries.
+     *
+     * @param dpId
+     *            the dpId
+     * @param tableId
+     *            the tableId
+     * @param flowId
+     *            the flowId
+     * @param priority
+     *            the priority
+     * @param flowName
+     *            the flow name
+     * @param idleTimeOut
+     *            the idle timeout
+     * @param hardTimeOut
+     *            the hard timeout
+     * @param cookie
+     *            the cookie
+     * @param matches
+     *            the list of matches to be writted
+     * @param instructions
+     *            the list of instruction to be written.
+     * @param addOrRemove
+     *            add or remove the entries.
      */
     protected void syncFlow(BigInteger dpId, short tableId, String flowId, int priority, String flowName,
-                          int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase>  matches,
-                          List<InstructionInfo> instructions, int addOrRemove) {
+            int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase> matches,
+            List<InstructionInfo> instructions, int addOrRemove) {
         if (addOrRemove == NwConstants.DEL_FLOW) {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,flowId,
-                priority, flowName , idleTimeOut, hardTimeOut, cookie, matches, null);
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName, idleTimeOut,
+                    hardTimeOut, cookie, matches, null);
             LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
             mdsalManager.removeFlow(flowEntity);
         } else {
-            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId,
-                priority, flowName, idleTimeOut, hardTimeOut, cookie, matches, instructions);
+            FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName, idleTimeOut,
+                    hardTimeOut, cookie, matches, instructions);
             LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
             mdsalManager.installFlow(flowEntity);
         }
@@ -275,4 +314,22 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
         return instructions;
     }
+
+    protected String getOperAsString(int flowOper) {
+        String oper;
+        switch (flowOper) {
+            case NwConstants.ADD_FLOW:
+                oper = "Add";
+                break;
+            case NwConstants.DEL_FLOW:
+                oper = "Del";
+                break;
+            case NwConstants.MOD_FLOW:
+                oper = "Mod";
+                break;
+            default:
+                oper = "UNKNOWN";
+        }
+        return oper;
+    }
 }