*/
package org.opendaylight.netvirt.aclservice;
+import com.google.common.collect.Lists;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.stream.Collectors;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
import org.opendaylight.genius.mdsalutil.ActionInfo;
-import org.opendaylight.genius.mdsalutil.ActionType;
import org.opendaylight.genius.mdsalutil.FlowEntity;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
-import org.opendaylight.genius.mdsalutil.InstructionType;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
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.utils.AclConntrackClassifierType;
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.netvirt.aclservice.utils.StatefulAclServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
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.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.ace.type.AceIp;
+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.ace.ip.ace.ip.version.AceIpv4;
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.DirectionBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
+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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 ManagedNewTransactionRunner txRunner;
+ protected final Class<? extends ServiceModeBase> serviceMode;
+ protected final AclDataUtil aclDataUtil;
+ protected final AclServiceUtils aclServiceUtils;
+ protected final JobCoordinator jobCoordinator;
+ protected final AclInterfaceCache aclInterfaceCache;
+
+ protected final Class<? extends DirectionBase> direction;
+ protected final String directionString;
/**
* 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 aclDataUtil the acl data util.
+ * @param aclServiceUtils the acl service util.
+ * @param jobCoordinator the job coordinator
+ * @param aclInterfaceCache the acl interface cache
*/
public AbstractAclServiceImpl(Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker,
- OdlInterfaceRpcService interfaceManager, IMdsalApiManager mdsalManager) {
+ IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil, AclServiceUtils aclServiceUtils,
+ JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
this.dataBroker = dataBroker;
- this.interfaceManager = interfaceManager;
+ this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
this.mdsalManager = mdsalManager;
this.serviceMode = serviceMode;
+ this.aclDataUtil = aclDataUtil;
+ this.aclServiceUtils = aclServiceUtils;
+ this.jobCoordinator = jobCoordinator;
+ this.aclInterfaceCache = aclInterfaceCache;
+
+ this.direction =
+ this.serviceMode.equals(ServiceModeEgress.class) ? DirectionIngress.class : DirectionEgress.class;
+ this.directionString = this.direction.equals(DirectionEgress.class) ? "Egress" : "Ingress";
}
@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());
+ if (port.getSecurityGroups() == null) {
+ LOG.info("Port {} without SGs", port.getInterfaceId());
+ return false;
+ }
+ BigInteger dpId = port.getDpId();
+ if (dpId == null || port.getLPortTag() == null) {
+ LOG.error("Unable to find DpId from ACL interface with id {}", port.getInterfaceId());
return false;
}
+ LOG.debug("Applying ACL on port {} with DpId {}", port, dpId);
+ programAcl(port, Action.ADD, NwConstants.ADD_FLOW);
+ updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
+ return true;
+ }
- programAclWithAllowedAddress(dpId, AclServiceUtils.getPortAllowedAddresses(port), interfaceState.getIfIndex(),
- AclServiceUtils.getInterfaceAcls(port), NwConstants.ADD_FLOW);
+ @Override
+ public boolean bindAcl(AclInterface port) {
+ if (port == null || port.getSecurityGroups() == null) {
+ LOG.error("Port and port security groups cannot be null for binding ACL service, port={}", port);
+ return false;
+ }
+ bindService(port);
+ if (port.getDpId() != null) {
+ updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
+ }
+ return true;
+ }
- // TODO: uncomment bindservice() when the acl flow programming is
- // implemented
- // bindService(port.getName());
+ @Override
+ public boolean unbindAcl(AclInterface port) {
+ if (port == null) {
+ LOG.error("Port cannot be null for unbinding ACL service");
+ return false;
+ }
+ if (port.getDpId() != null) {
+ unbindService(port);
+ updateRemoteAclFilterTable(port, NwConstants.DEL_FLOW);
+ }
return true;
}
@Override
- public boolean updateAcl(Interface portBefore, Interface portAfter) {
- boolean result = false;
- boolean isPortSecurityEnable = AclServiceUtils.isPortSecurityEnabled(portAfter);
- boolean isPortSecurityEnableBefore = AclServiceUtils.isPortSecurityEnabled(portBefore);
+ public boolean updateAcl(AclInterface portBefore, AclInterface portAfter) {
+ // this check is to avoid situations of port update coming before interface state is up
+ if (portAfter.getDpId() == null || portAfter.getLPortTag() == null) {
+ LOG.debug("Unable to find DpId from ACL interface with id {} and lport {}", portAfter.getInterfaceId(),
+ portAfter.getLPortTag());
+ return false;
+ }
+ boolean result = true;
+ boolean isPortSecurityEnable = portAfter.isPortSecurityEnabled();
+ boolean isPortSecurityEnableBefore = portBefore.isPortSecurityEnabled();
// if port security is changed, apply/remove Acls
if (isPortSecurityEnableBefore != isPortSecurityEnable) {
+ LOG.debug("On ACL update, Port security is {} for {}", isPortSecurityEnable ? "Enabled" :
+ "Disabled", portAfter.getInterfaceId());
if (isPortSecurityEnable) {
result = applyAcl(portAfter);
} else {
- result = removeAcl(portAfter);
+ result = removeAcl(portBefore);
}
} else if (isPortSecurityEnable) {
// Acls has been updated, find added/removed Acls and act accordingly.
- this.processInterfaceUpdate(portBefore, portAfter);
+ processInterfaceUpdate(portBefore, portAfter);
+ LOG.debug("On ACL update, ACL has been updated for {}", portAfter.getInterfaceId());
}
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);
- List<AllowedAddressPairs> addedAllowedAddressPairs =
- AclServiceUtils.getUpdatedAllowedAddressPairs(portAfter,portBefore);
- List<AllowedAddressPairs> deletedAllowedAddressPairs =
- AclServiceUtils.getUpdatedAllowedAddressPairs(portBefore, portAfter);
- if (addedAllowedAddressPairs != null && !addedAllowedAddressPairs.isEmpty()) {
- programAclWithAllowedAddress(dpId, addedAllowedAddressPairs, interfaceState.getIfIndex(),
- AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.ADD_FLOW);
+ private void processInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
+ BigInteger dpId = portAfter.getDpId();
+ List<AllowedAddressPairs> addedAaps = AclServiceUtils
+ .getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
+ List<AllowedAddressPairs> deletedAaps = AclServiceUtils
+ .getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
+ if (deletedAaps != null && !deletedAaps.isEmpty()) {
+ programAclWithAllowedAddress(portBefore, deletedAaps, Action.UPDATE, NwConstants.DEL_FLOW);
+ updateRemoteAclFilterTable(portBefore, portBefore.getSecurityGroups(), deletedAaps, NwConstants.DEL_FLOW);
}
- if (deletedAllowedAddressPairs != null && !deletedAllowedAddressPairs.isEmpty()) {
- programAclWithAllowedAddress(dpId, deletedAllowedAddressPairs, interfaceState.getIfIndex(),
- AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.DEL_FLOW);
+ if (addedAaps != null && !addedAaps.isEmpty()) {
+ programAclWithAllowedAddress(portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
+ updateRemoteAclFilterTable(portAfter, portAfter.getSecurityGroups(), addedAaps, NwConstants.ADD_FLOW);
}
+ updateArpForAllowedAddressPairs(dpId, portAfter.getLPortTag(), deletedAaps, portAfter.getAllowedAddressPairs());
+ if (portAfter.getSubnetIpPrefixes() != null && portBefore.getSubnetIpPrefixes() == null) {
+ programBroadcastRules(portAfter, NwConstants.ADD_FLOW);
+ }
+
+ List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter.getSecurityGroups(),
+ portBefore.getSecurityGroups());
+ List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore.getSecurityGroups(),
+ portAfter.getSecurityGroups());
+ if (deletedAcls.isEmpty() && addedAcls.isEmpty()) {
+ LOG.trace("No change w.r.t ACL list for port={}", portAfter.getInterfaceId());
+ return;
+ }
+
+ handleAclChange(portBefore, deletedAcls, NwConstants.DEL_FLOW);
+ handleAclChange(portAfter, addedAcls, NwConstants.ADD_FLOW);
+ }
+
+ private void handleAclChange(AclInterface port, List<Uuid> aclList, int addOrRemove) {
+ int operationForAclRules = (addOrRemove == NwConstants.DEL_FLOW) ? NwConstants.MOD_FLOW : addOrRemove;
+ programAclRules(port, aclList, operationForAclRules);
+ updateRemoteAclFilterTable(port, aclList, port.getAllowedAddressPairs(), addOrRemove);
+ programAclDispatcherTable(port, addOrRemove);
+ }
+
+ protected SortedSet<Integer> getRemoteAclTags(AclInterface port) {
+ return this.direction == DirectionIngress.class ? port.getIngressRemoteAclTags()
+ : port.getEgressRemoteAclTags();
+ }
- List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter, portBefore);
- List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore, portAfter);
- if (addedAcls != null && !addedAcls.isEmpty()) {
- updateCustomRules(dpId, interfaceState.getIfIndex(), addedAcls, NwConstants.ADD_FLOW);
+ protected void programAclDispatcherTable(AclInterface port, int addOrRemove) {
+ SortedSet<Integer> remoteAclTags = getRemoteAclTags(port);
+ if (remoteAclTags.isEmpty()) {
+ LOG.debug("No {} rules with remote group id for port={}", this.directionString, port.getInterfaceId());
+ return;
}
- if (deletedAcls != null && !deletedAcls.isEmpty()) {
- updateCustomRules(dpId, interfaceState.getIfIndex(), deletedAcls, NwConstants.DEL_FLOW);
+ Integer firstRemoteAclTag = remoteAclTags.first();
+ Integer lastRemoteAclTag = remoteAclTags.last();
+
+ programFirstRemoteAclEntryInDispatcherTable(port, firstRemoteAclTag, addOrRemove);
+ programLastRemoteAclEntryInDispatcherTable(port, lastRemoteAclTag, addOrRemove);
+
+ Integer previousRemoteAclTag = firstRemoteAclTag;
+ for (Integer remoteAclTag : remoteAclTags) {
+ if (remoteAclTag.equals(firstRemoteAclTag)) {
+ continue;
+ }
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(),
+ previousRemoteAclTag, serviceMode));
+ String flowId = this.directionString + "_ACL_Dispatcher_" + port.getDpId() + "_" + port.getLPortTag() + "_"
+ + remoteAclTag;
+
+ List<InstructionInfo> instructions =
+ AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
+ instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(remoteAclTag));
+ syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId,
+ AclConstants.ACE_GOTO_NEXT_REMOTE_ACL_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
+ instructions, addOrRemove);
+
+ previousRemoteAclTag = remoteAclTag;
}
}
- private void updateCustomRules(BigInteger dpId, int lportTag, List<Uuid> aclUuidList, int action) {
- programAclRules(aclUuidList, dpId, lportTag, action);
+ protected void programFirstRemoteAclEntryInDispatcherTable(AclInterface port, Integer firstRemoteAclTag,
+ int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
+ String flowId = this.directionString + "_ACL_Dispatcher_First_" + port.getDpId() + "_" + port.getLPortTag()
+ + "_" + firstRemoteAclTag;
+
+ List<InstructionInfo> instructions =
+ AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
+ instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(firstRemoteAclTag));
+ syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId, AclConstants.ACE_FIRST_REMOTE_ACL_PRIORITY,
+ "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
}
- 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);
+ protected void programLastRemoteAclEntryInDispatcherTable(AclInterface port, Integer lastRemoteAclTag,
+ int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(), lastRemoteAclTag,
+ serviceMode));
+ String flowId = this.directionString + "_ACL_Dispatcher_Last_" + port.getDpId() + "_" + port.getLPortTag() + "_"
+ + lastRemoteAclTag;
+
+ List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
+ syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId, AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY,
+ "ACL", 0, 0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
}
- @Override
- public boolean removeAcl(Interface port) {
- if (!AclServiceUtils.isPortSecurityEnabled(port)) {
- return false;
+ private void programAcl(AclInterface port, Action action, int addOrRemove) {
+ programAclWithAllowedAddress(port, port.getAllowedAddressPairs(), action, addOrRemove);
+ }
+
+ private void programAclWithAllowedAddress(AclInterface port, List<AllowedAddressPairs> allowedAddresses,
+ Action action, int addOrRemove) {
+ BigInteger dpId = port.getDpId();
+ int lportTag = port.getLPortTag();
+ LOG.debug("Applying ACL Allowed Address on DpId {}, lportTag {}, Action {}", dpId, lportTag, action);
+ String portId = port.getInterfaceId();
+ programGeneralFixedRules(port, "", allowedAddresses, action, addOrRemove);
+ programAclPortSpecificFixedRules(dpId, allowedAddresses, lportTag, portId, action, addOrRemove);
+ if (action == Action.ADD || action == Action.REMOVE) {
+ programAclRules(port, port.getSecurityGroups(), addOrRemove);
+ programAclDispatcherTable(port, addOrRemove);
}
- 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);
+ }
+
- // TODO: uncomment unbindService() when the acl flow programming is
- // implemented
- // unbindService(port.getName());
+ /**
+ * Programs the acl custom rules.
+ *
+ * @param port acl interface
+ * @param aclUuidList the list of acl uuid to be applied
+ * @param addOrRemove whether to delete or add flow
+ * @return program succeeded
+ */
+ protected boolean programAclRules(AclInterface port, List<Uuid> aclUuidList, int addOrRemove) {
+ BigInteger dpId = port.getDpId();
+ LOG.debug("Applying custom rules on DpId {}, lportTag {}", dpId, port.getLPortTag());
+ if (aclUuidList == null || dpId == null) {
+ LOG.warn("{} ACL parameters can not be null. dpId={}, aclUuidList={}", this.directionString, dpId,
+ aclUuidList);
+ return false;
+ }
+ for (Uuid aclUuid : aclUuidList) {
+ Acl acl = AclServiceUtils.getAcl(dataBroker, aclUuid.getValue());
+ if (null == acl) {
+ LOG.warn("The ACL {} not found in config DS", aclUuid.getValue());
+ continue;
+ }
+ AccessListEntries accessListEntries = acl.getAccessListEntries();
+ List<Ace> aceList = accessListEntries.getAce();
+ for (Ace ace: aceList) {
+ programAceRule(port, ace, addOrRemove);
+ }
+ }
return true;
}
+ /**
+ * Programs the ace specific rule.
+ *
+ * @param port acl interface
+ * @param ace rule to be program
+ * @param addOrRemove whether to delete or add flow
+ */
+ protected void programAceRule(AclInterface port, Ace ace, int addOrRemove) {
+ SecurityRuleAttr aceAttr = AclServiceUtils.getAccesssListAttributes(ace);
+ if (!isValidDirection(aceAttr.getDirection())) {
+ LOG.trace("Ignoring {} direction while processing for {} ACE Rule {}", aceAttr.getDirection(),
+ this.directionString, ace.getRuleName());
+ return;
+ }
+ LOG.debug("Program {} ACE rule for dpId={}, lportTag={}, addOrRemove={}, ace={}, portId={}",
+ this.directionString, port.getDpId(), port.getLPortTag(), addOrRemove, ace.getRuleName(),
+ port.getInterfaceId());
+
+ Matches matches = ace.getMatches();
+ Map<String, List<MatchInfoBase>> flowMap = null;
+ if (matches.getAceType() instanceof AceIp) {
+ flowMap = AclServiceOFFlowBuilder.programIpFlow(matches);
+ if (!AclServiceUtils.doesAceHaveRemoteGroupId(aceAttr)) {
+ // programming for ACE which doesn't have any remote group Id
+ programForAceNotHavingRemoteAclId(port, ace, flowMap, addOrRemove);
+ } else {
+ Uuid remoteAclId = aceAttr.getRemoteGroupId();
+ // programming for ACE which have remote group Id
+ programAceSpecificFlows(port, ace, flowMap, remoteAclId, addOrRemove);
+ }
+ }
+ }
+
+ protected void programForAceNotHavingRemoteAclId(AclInterface port, Ace ace,
+ Map<String, List<MatchInfoBase>> flowMap, int addOrRemove) {
+ if (null == flowMap) {
+ return;
+ }
+
+ MatchInfoBase lportTagMatch = AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode);
+ for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
+ String flowName = entry.getKey();
+ List<MatchInfoBase> matches = entry.getValue();
+ matches.add(lportTagMatch);
+ String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
+ + ace.getKey().getRuleName();
+
+ List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
+ int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
+ syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId,
+ AclConstants.ACE_WITHOUT_REMOTE_ACL_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
+ instructions, operation);
+
+ if (addOrRemove != NwConstants.DEL_FLOW) {
+ programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches,
+ AclConstants.ACE_WITHOUT_REMOTE_ACL_PRIORITY);
+ }
+ }
+ }
+
+ protected void programAceSpecificFlows(AclInterface port, Ace ace, Map<String, List<MatchInfoBase>> flowMap,
+ Uuid remoteAclId, int addOrRemove) {
+ if (null == flowMap) {
+ return;
+ }
+ Integer remoteAclTag = this.aclServiceUtils.getAclTag(remoteAclId);
+ if (remoteAclTag == null || remoteAclTag == AclConstants.INVALID_ACL_TAG) {
+ LOG.error("Failed building metadata match for ACL={}. Failed to allocate id", remoteAclId.getValue());
+ return;
+ }
+
+ for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
+ String flowName = entry.getKey();
+ List<MatchInfoBase> matches = entry.getValue();
+ matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(),
+ remoteAclTag, serviceMode));
+ String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
+ + ace.getKey().getRuleName();
+
+ List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRemoteAclTable());
+ int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
+ syncFlow(port.getDpId(), getAclRuleBasedFilterTable(), flowId, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0,
+ 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
+
+ if (addOrRemove != NwConstants.DEL_FLOW) {
+ programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches,
+ AclConstants.ACL_DEFAULT_PRIORITY);
+ }
+ }
+ }
+
+ private void programAclForExistingTrafficTable(AclInterface port, Ace ace, int addOrRemove, String flowName,
+ List<MatchInfoBase> matches, Integer priority) {
+ AceIp acl = (AceIp) ace.getMatches().getAceType();
+ final String newFlowName = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag()
+ + "_" + ((acl.getAceIpVersion() instanceof AceIpv4) ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
+
+ final List<MatchInfoBase> newMatches =
+ matches.stream().filter(obj -> !(obj instanceof NxMatchCtState || obj instanceof MatchMetadata))
+ .collect(Collectors.toList());
+ newMatches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
+ newMatches.add(new NxMatchCtState(AclConstants.TRACKED_RPL_CT_STATE, AclConstants.TRACKED_RPL_CT_STATE_MASK));
+
+ List<InstructionInfo> instructions = StatefulAclServiceHelper
+ .createCtMarkInstructionForNewState(getAclFilterCumDispatcherTable(), port.getElanId());
+ // Reversing the flow add/delete operation for this table.
+ int operation = (addOrRemove == NwConstants.ADD_FLOW) ? NwConstants.DEL_FLOW : NwConstants.ADD_FLOW;
+ syncFlow(port.getDpId(), getAclForExistingTrafficTable(), newFlowName, priority, "ACL", 0,
+ StatefulAclServiceHelper.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
+ AclConstants.COOKIE_ACL_BASE, newMatches, instructions, operation);
+ }
+
@Override
- public boolean applyAce(Interface port, Ace ace) {
- 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());
- programAceRule(dpId, interfaceState.getIfIndex(), NwConstants.ADD_FLOW, ace);
+ programAcl(port, Action.REMOVE, NwConstants.DEL_FLOW);
+ updateRemoteAclFilterTable(port, NwConstants.DEL_FLOW);
return true;
}
@Override
- public boolean removeAce(Interface port, Ace ace) {
- if (!AclServiceUtils.isPortSecurityEnabled(port)) {
+ public boolean applyAce(AclInterface port, String aclName, Ace ace) {
+ if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
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, ace, NwConstants.ADD_FLOW);
+ // TODO: If this is the first port on the DPN for a remote ACL, add
+ // remote ACL flows.
+ // updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
return true;
}
+ @Override
+ public boolean removeAce(AclInterface port, String aclName, Ace ace) {
+ if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
+ return false;
+ }
+ programAceRule(port, ace, NwConstants.MOD_FLOW);
+ // TODO: If this is the last port on the DPN for a remote ACL, delete
+ // remote ACL flows.
+ // updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
+ return true;
+ }
/**
* Bind service.
*
- * @param interfaceName the interface name
+ * @param aclInterface the acl interface
*/
- protected abstract void bindService(String interfaceName);
+ public abstract void bindService(AclInterface aclInterface);
/**
* Unbind service.
*
- * @param interfaceName the interface name
+ * @param aclInterface the acl interface
*/
- protected abstract void unbindService(String interfaceName);
+ protected abstract void unbindService(AclInterface aclInterface);
/**
- * Program the default anti-spoofing rule and the conntrack rules.
+ * 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 programFixedRules(BigInteger dpid, String dhcpMacAddress,
- List<AllowedAddressPairs> allowedAddresses, int lportTag, int addOrRemove);
+ protected abstract void programGeneralFixedRules(AclInterface port, String dhcpMacAddress,
+ List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove);
/**
- * Programs the acl custom rules.
+ * Update arp for allowed address pairs.
*
- * @param aclUuidList the list of acl uuid to be applied
- * @param dpId the dpId
+ * @param dpId the dp id
* @param lportTag the lport tag
- * @param addOrRemove whether to delete or add flow
+ * @param deletedAAP the deleted allowed address pairs
+ * @param addedAAP the added allowed address pairs
*/
- protected abstract void programAclRules(List<Uuid> aclUuidList, BigInteger dpId, int lportTag, int addOrRemove);
+ protected abstract void updateArpForAllowedAddressPairs(BigInteger dpId, int lportTag,
+ List<AllowedAddressPairs> deletedAAP, List<AllowedAddressPairs> addedAAP);
/**
- * Programs the ace custom rule.
+ * Programs broadcast rules.
*
- * @param dpId the dpId
- * @param lportTag the lport tag
+ * @param port the Acl Interface port
* @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 programBroadcastRules(AclInterface port, int addOrRemove);
/**
* 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) {
- if (addOrRemove == NwConstants.DEL_FLOW) {
- 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);
- LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
- mdsalManager.installFlow(flowEntity);
- }
+ int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase> matches,
+ List<InstructionInfo> instructions, int addOrRemove) {
+ jobCoordinator.enqueueJob(flowName, () -> {
+ if (addOrRemove == NwConstants.DEL_FLOW) {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
+ idleTimeOut, hardTimeOut, cookie, matches, null);
+ LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
+
+ return Collections.singletonList(mdsalManager.removeFlow(dpId, flowEntity));
+
+ } else {
+ FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
+ idleTimeOut, hardTimeOut, cookie, matches, instructions);
+ LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
+ return Collections.singletonList(mdsalManager.installFlow(dpId, flowEntity));
+ }
+ });
+ }
+
+ protected List<InstructionInfo> getDispatcherTableResubmitInstructions() {
+ return getDispatcherTableResubmitInstructions(new ArrayList<>());
}
/**
- * Gets the dispatcher table resubmit instructions based on ingress/egress
- * service mode w.r.t switch.
+ * Gets the dispatcher table resubmit instructions based on ingress/egress service mode w.r.t switch.
*
- * @param actionsInfos the actions infos
+ * @param actionsInfos
+ * the actions infos
* @return the instructions for dispatcher table resubmit
*/
protected List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos) {
short dispatcherTableId = NwConstants.LPORT_DISPATCHER_TABLE;
if (ServiceModeEgress.class.equals(this.serviceMode)) {
- dispatcherTableId = AclConstants.EGRESS_LPORT_DISPATCHER_TABLE;
+ dispatcherTableId = NwConstants.EGRESS_LPORT_DISPATCHER_TABLE;
}
List<InstructionInfo> instructions = new ArrayList<>();
- actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] {Short.toString(dispatcherTableId)}));
- instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+ actionsInfos.add(new ActionNxResubmit(dispatcherTableId));
+ instructions.add(new InstructionApplyActions(actionsInfos));
return instructions;
}
+
+ private void updateRemoteAclFilterTable(AclInterface port, int addOrRemove) {
+ updateRemoteAclFilterTable(port, port.getSecurityGroups(), port.getAllowedAddressPairs(), addOrRemove);
+ }
+
+ private void updateRemoteAclFilterTable(AclInterface port, List<Uuid> aclList, List<AllowedAddressPairs> aaps,
+ int addOrRemove) {
+ if (aclList == null) {
+ LOG.debug("Port {} without SGs", port.getInterfaceId());
+ return;
+ }
+ for (Uuid acl : aclList) {
+ if (aclDataUtil.getRemoteAcl(acl) != null) {
+ Map<String, Set<AclInterface>> mapAclWithPortSet = aclDataUtil.getRemoteAclInterfaces(acl);
+ Set<BigInteger> dpns = collectDpns(mapAclWithPortSet);
+ Integer aclTag = aclServiceUtils.getAclTag(acl);
+
+ for (AllowedAddressPairs ip : aaps) {
+ if (!AclServiceUtils.isNotIpv4AllNetwork(ip)) {
+ continue;
+ }
+ for (BigInteger dpId : dpns) {
+ programRemoteAclTableFlow(dpId, aclTag, ip, addOrRemove);
+ }
+ }
+ syncRemoteAclTableFromOtherDpns(port, acl, aclTag, addOrRemove);
+ }
+ }
+ }
+
+ private void syncRemoteAclTableFromOtherDpns(AclInterface port, Uuid acl, Integer aclTag, int addOrRemove) {
+ Collection<AclInterface> aclInterfaces = aclDataUtil.getInterfaceList(acl);
+ BigInteger dpId = port.getDpId();
+ boolean isFirstPortInDpn = true;
+ if (aclInterfaces != null) {
+ for (AclInterface aclInterface : aclInterfaces) {
+ if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
+ continue;
+ }
+ if (dpId.equals(aclInterface.getDpId())) {
+ isFirstPortInDpn = false;
+ break;
+ }
+ }
+ if (isFirstPortInDpn) {
+ for (AclInterface aclInterface : aclInterfaces) {
+ if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
+ continue;
+ }
+ for (AllowedAddressPairs ip : aclInterface.getAllowedAddressPairs()) {
+ programRemoteAclTableFlow(port.getDpId(), aclTag, ip, addOrRemove);
+ }
+ }
+ }
+ }
+ }
+
+ protected abstract void programRemoteAclTableFlow(BigInteger dpId, Integer aclTag, AllowedAddressPairs ip,
+ int addOrRemove);
+
+ 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;
+ }
+
+ protected Set<BigInteger> collectDpns(Map<String, Set<AclInterface>> mapAclWithPortSet) {
+ Set<BigInteger> dpns = new HashSet<>();
+ if (mapAclWithPortSet == null) {
+ return dpns;
+ }
+ for (Set<AclInterface> innerSet : mapAclWithPortSet.values()) {
+ if (innerSet == null) {
+ continue;
+ }
+ for (AclInterface inter : innerSet) {
+ dpns.add(inter.getDpId());
+ }
+ }
+ return dpns;
+ }
+
+ /**
+ * Programs the port specific fixed rules.
+ *
+ * @param dpId the dp id
+ * @param allowedAddresses the allowed addresses
+ * @param lportTag the lport tag
+ * @param portId the portId
+ * @param action the action
+ * @param write whether to add or remove the flow.
+ */
+ protected void programAclPortSpecificFixedRules(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses,
+ int lportTag, String portId, Action action, int write) {
+ programGotoClassifierTableRules(dpId, allowedAddresses, lportTag, write);
+ if (action == Action.ADD || action == Action.REMOVE) {
+ programConntrackRecircRules(dpId, allowedAddresses, lportTag, portId, write);
+ programPortSpecificDropRules(dpId, lportTag, write);
+ programAclCommitRules(dpId, lportTag, portId, write);
+ }
+ LOG.info("programAclPortSpecificFixedRules: flows for dpId={}, lportId={}, action={}, write={}", dpId, lportTag,
+ action, write);
+ }
+
+ protected abstract void programGotoClassifierTableRules(BigInteger dpId, List<AllowedAddressPairs> aaps,
+ int lportTag, int addOrRemove);
+
+ /**
+ * Adds the rule to send the packet to the netfilter to check whether it is a known packet.
+ *
+ * @param dpId the dpId
+ * @param aaps the allowed address pairs
+ * @param lportTag the lport tag
+ * @param portId the portId
+ * @param addOrRemove whether to add or remove the flow
+ */
+ protected void programConntrackRecircRules(BigInteger dpId, List<AllowedAddressPairs> aaps, int lportTag,
+ String portId, int addOrRemove) {
+ if (AclServiceUtils.doesIpv4AddressExists(aaps)) {
+ programConntrackRecircRule(dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
+ }
+ if (AclServiceUtils.doesIpv6AddressExists(aaps)) {
+ programConntrackRecircRule(dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
+ }
+ }
+
+ protected void programConntrackRecircRule(BigInteger dpId, int lportTag, String portId,
+ MatchEthernetType matchEtherType, int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(matchEtherType);
+ matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
+
+ List<InstructionInfo> instructions = new ArrayList<>();
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ Long elanTag = getElanIdFromAclInterface(portId);
+ if (elanTag == null) {
+ LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={},", portId,
+ dpId, lportTag, addOrRemove);
+ return;
+ }
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ actionsInfos.add(new ActionNxConntrack(2, 0, 0, elanTag.intValue(), getAclForExistingTrafficTable()));
+ instructions.add(new InstructionApplyActions(actionsInfos));
+ }
+
+ String flowName =
+ this.directionString + "_Fixed_Conntrk_" + dpId + "_" + lportTag + "_" + matchEtherType + "_Recirc";
+ syncFlow(dpId, getAclConntrackSenderTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
+ AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+ }
+
+ /**
+ * Adds the rules to drop the unknown/invalid packets .
+ *
+ * @param dpId the dpId
+ * @param lportTag the lport tag
+ * @param addOrRemove whether to add or remove the flow
+ */
+ protected void programPortSpecificDropRules(BigInteger dpId, int lportTag, int addOrRemove) {
+ LOG.debug("Programming Drop Rules: DpId={}, lportTag={}, addOrRemove={}", dpId, lportTag, addOrRemove);
+ programConntrackInvalidDropRule(dpId, lportTag, addOrRemove);
+ programAclRuleMissDropRule(dpId, lportTag, addOrRemove);
+ }
+
+ /**
+ * Adds the rule to drop the conntrack invalid packets .
+ *
+ * @param dpId the dpId
+ * @param lportTag the lport tag
+ * @param addOrRemove whether to add or remove the flow
+ */
+ protected void programConntrackInvalidDropRule(BigInteger dpId, int lportTag, int addOrRemove) {
+ List<MatchInfoBase> matches = AclServiceOFFlowBuilder.addLPortTagMatches(lportTag,
+ AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, serviceMode);
+ List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
+
+ String flowId = this.directionString + "_Fixed_Conntrk_Drop" + dpId + "_" + lportTag + "_Tracked_Invalid";
+ syncFlow(dpId, getAclFilterCumDispatcherTable(), flowId, AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, "ACL",
+ 0, 0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
+ }
+
+ /**
+ * Program ACL rule miss drop rule for a port.
+ *
+ * @param dpId the dp id
+ * @param lportTag the lport tag
+ * @param addOrRemove the add or remove
+ */
+ protected void programAclRuleMissDropRule(BigInteger dpId, int lportTag, int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
+ List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
+
+ String flowId = this.directionString + "_Fixed_Acl_Rule_Miss_Drop_" + dpId + "_" + lportTag;
+ syncFlow(dpId, getAclFilterCumDispatcherTable(), flowId, AclConstants.CT_STATE_TRACKED_NEW_DROP_PRIORITY, "ACL",
+ 0, 0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
+ }
+
+ /**
+ * Program acl commit rules.
+ *
+ * @param dpId the dp id
+ * @param lportTag the lport tag
+ * @param portId the port id
+ * @param addOrRemove the add or remove
+ */
+ protected void programAclCommitRules(BigInteger dpId, int lportTag, String portId, int addOrRemove) {
+ programAclCommitRuleForConntrack(dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
+ programAclCommitRuleForConntrack(dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
+ programAclCommitRuleForNonConntrack(dpId, lportTag, addOrRemove);
+ }
+
+ /**
+ * Program acl commit rule for conntrack.
+ *
+ * @param dpId the dp id
+ * @param lportTag the lport tag
+ * @param portId the port id
+ * @param matchEtherType the match ether type
+ * @param addOrRemove the add or remove
+ */
+ protected void programAclCommitRuleForConntrack(BigInteger dpId, int lportTag, String portId,
+ MatchEthernetType matchEtherType, int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(matchEtherType);
+ matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
+ matches.add(
+ AclServiceUtils.buildAclConntrackClassifierTypeMatch(AclConntrackClassifierType.CONNTRACK_SUPPORTED));
+
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ if (addOrRemove == NwConstants.ADD_FLOW) {
+ Long elanId = getElanIdFromAclInterface(portId);
+ if (elanId == null) {
+ LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={}", portId, dpId,
+ lportTag, addOrRemove);
+ return;
+ }
+ List<NxCtAction> ctActionsList =
+ Lists.newArrayList(new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_EST_STATE));
+ actionsInfos.add(new ActionNxConntrack(2, 1, 0, elanId.intValue(), (short) 255, ctActionsList));
+ }
+ List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
+
+ String flowName = directionString + "_Acl_Commit_Conntrack_" + dpId + "_" + lportTag + "_" + matchEtherType;
+ // Flow for conntrack traffic to commit and resubmit to dispatcher
+ syncFlow(dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
+ AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+ }
+
+ /**
+ * Program acl commit rule for non conntrack.
+ *
+ * @param dpId the dp id
+ * @param lportTag the lport tag
+ * @param addOrRemove the add or remove
+ */
+ protected void programAclCommitRuleForNonConntrack(BigInteger dpId, int lportTag, int addOrRemove) {
+ List<MatchInfoBase> matches = new ArrayList<>();
+ matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
+ matches.add(AclServiceUtils
+ .buildAclConntrackClassifierTypeMatch(AclConntrackClassifierType.NON_CONNTRACK_SUPPORTED));
+
+ List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
+ String flowName = this.directionString + "_Acl_Commit_Non_Conntrack_" + dpId + "_" + lportTag;
+ // Flow for non-conntrack traffic to resubmit to dispatcher
+ syncFlow(dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
+ AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+ }
+
+ protected Long getElanIdFromAclInterface(String elanInterfaceName) {
+ AclInterface aclInterface = aclInterfaceCache.get(elanInterfaceName);
+ if (null != aclInterface) {
+ return aclInterface.getElanId();
+ }
+ return null;
+ }
+
+ protected abstract boolean isValidDirection(Class<? extends DirectionBase> direction);
+
+ protected abstract short getAclAntiSpoofingTable();
+
+ protected abstract short getAclConntrackClassifierTable();
+
+ protected abstract short getAclConntrackSenderTable();
+
+ protected abstract short getAclForExistingTrafficTable();
+
+ protected abstract short getAclFilterCumDispatcherTable();
+
+ protected abstract short getAclRuleBasedFilterTable();
+
+ protected abstract short getAclRemoteAclTable();
+
+ protected abstract short getAclCommitterTable();
}