Manage Acl For Existing TrafficTable Throwing Exception
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractAclServiceImpl.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.aclservice;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.collect.Lists;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
23 import java.util.SortedSet;
24 import java.util.stream.Collectors;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.mdsalutil.ActionInfo;
30 import org.opendaylight.genius.mdsalutil.FlowEntity;
31 import org.opendaylight.genius.mdsalutil.InstructionInfo;
32 import org.opendaylight.genius.mdsalutil.MDSALUtil;
33 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
34 import org.opendaylight.genius.mdsalutil.NwConstants;
35 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
36 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxCtClear;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
42 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
43 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
44 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
45 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
46 import org.opendaylight.netvirt.aclservice.api.AclServiceListener;
47 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
48 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
49 import org.opendaylight.netvirt.aclservice.utils.AclConntrackClassifierType;
50 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
51 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
52 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
53 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
56 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;
57 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;
58 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;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl.InterfaceType;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.SubnetInfo;
69 import org.opendaylight.yangtools.yang.common.Uint64;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public abstract class AbstractAclServiceImpl implements AclServiceListener {
74
75     private static final Logger LOG = LoggerFactory.getLogger(AbstractAclServiceImpl.class);
76
77     protected final IMdsalApiManager mdsalManager;
78     protected final ManagedNewTransactionRunner txRunner;
79     protected final Class<? extends ServiceModeBase> serviceMode;
80     protected final AclDataUtil aclDataUtil;
81     protected final AclServiceUtils aclServiceUtils;
82     protected final JobCoordinator jobCoordinator;
83     protected final AclInterfaceCache aclInterfaceCache;
84
85     protected final Class<? extends DirectionBase> direction;
86     protected final String directionString;
87
88     /**
89      * Initialize the member variables.
90      *
91      * @param serviceMode the service mode
92      * @param dataBroker the data broker instance.
93      * @param mdsalManager the mdsal manager instance.
94      * @param aclDataUtil the acl data util.
95      * @param aclServiceUtils the acl service util.
96      * @param jobCoordinator the job coordinator
97      * @param aclInterfaceCache the acl interface cache
98      */
99     public AbstractAclServiceImpl(Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker,
100             IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil, AclServiceUtils aclServiceUtils,
101             JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
102         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
103         this.mdsalManager = mdsalManager;
104         this.serviceMode = serviceMode;
105         this.aclDataUtil = aclDataUtil;
106         this.aclServiceUtils = aclServiceUtils;
107         this.jobCoordinator = jobCoordinator;
108         this.aclInterfaceCache = aclInterfaceCache;
109
110         this.direction =
111                 this.serviceMode.equals(ServiceModeEgress.class) ? DirectionIngress.class : DirectionEgress.class;
112         this.directionString = this.direction.equals(DirectionEgress.class) ? "Egress" : "Ingress";
113     }
114
115     @Override
116     public boolean applyAcl(AclInterface port) {
117         if (port == null) {
118             LOG.error("port cannot be null");
119             return false;
120         }
121         BigInteger dpId = port.getDpId();
122         if (dpId == null || port.getLPortTag() == null) {
123             LOG.error("Unable to find DpId from ACL interface with id {}", port.getInterfaceId());
124             return false;
125         }
126
127         LOG.debug("Applying ACL on port {} with DpId {}", port, dpId);
128         List<FlowEntity> flowEntries = new ArrayList<>();
129         if (port.getInterfaceType() == InterfaceType.DhcpService) {
130             programDhcpService(flowEntries, port, Action.ADD, NwConstants.ADD_FLOW);
131         } else {
132             if (port.getSecurityGroups() == null) {
133                 LOG.info("Port {} without SGs", port.getInterfaceId());
134                 return false;
135             }
136             programAcl(flowEntries, port, Action.ADD, NwConstants.ADD_FLOW);
137             updateRemoteAclFilterTable(flowEntries, port, NwConstants.ADD_FLOW);
138         }
139         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.ADD_FLOW);
140         return true;
141     }
142
143     @Override
144     public boolean bindAcl(AclInterface port) {
145         if (port == null) {
146             LOG.error("Port cannot be null for binding ACL service");
147             return false;
148         }
149         bindService(port);
150         return true;
151     }
152
153     @Override
154     public boolean unbindAcl(AclInterface port) {
155         if (port == null) {
156             LOG.error("Port cannot be null for unbinding ACL service");
157             return false;
158         }
159         if (port.getDpId() != null) {
160             unbindService(port);
161         }
162         return true;
163     }
164
165     @Override
166     public boolean updateAcl(AclInterface portBefore, AclInterface portAfter) {
167         // this check is to avoid situations of port update coming before interface state is up
168         if (portAfter.getDpId() == null || portAfter.getLPortTag() == null) {
169             LOG.debug("Unable to find DpId from ACL interface with id {} and lport {}", portAfter.getInterfaceId(),
170                     portAfter.getLPortTag());
171             return false;
172         }
173         boolean result = true;
174         boolean isPortSecurityEnable = portAfter.isPortSecurityEnabled();
175         boolean isPortSecurityEnableBefore = portBefore.isPortSecurityEnabled();
176         // if port security is changed, apply/remove Acls
177         if (isPortSecurityEnableBefore != isPortSecurityEnable) {
178             LOG.debug("On ACL update, Port security is {} for {}", isPortSecurityEnable ? "Enabled" :
179                     "Disabled", portAfter.getInterfaceId());
180             if (isPortSecurityEnable) {
181                 result = applyAcl(portAfter);
182             } else {
183                 result = removeAcl(portBefore);
184             }
185         } else if (isPortSecurityEnable) {
186             // Acls has been updated, find added/removed Acls and act accordingly.
187             processInterfaceUpdate(portBefore, portAfter);
188             LOG.debug("On ACL update, ACL has been updated for {}", portAfter.getInterfaceId());
189         } else if (portAfter.getInterfaceType() == InterfaceType.DhcpService) {
190             processDhcpServiceInterfaceUpdate(portBefore, portAfter);
191         }
192
193         return result;
194     }
195
196     private void processDhcpServiceInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
197         List<FlowEntity> addFlowEntries = new ArrayList<>();
198         List<FlowEntity> deleteFlowEntries = new ArrayList<>();
199         List<AllowedAddressPairs> addedAaps = AclServiceUtils
200                 .getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
201         List<AllowedAddressPairs> deletedAaps = AclServiceUtils
202                 .getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
203         if (!deletedAaps.isEmpty()) {
204             processDhcpServiceUpdate(deleteFlowEntries, portBefore, deletedAaps, NwConstants.DEL_FLOW);
205         }
206         if (!addedAaps.isEmpty()) {
207             processDhcpServiceUpdate(addFlowEntries, portAfter, addedAaps, NwConstants.ADD_FLOW);
208         }
209         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), deleteFlowEntries,
210                 NwConstants.DEL_FLOW);
211         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), addFlowEntries,
212                 NwConstants.ADD_FLOW);
213     }
214
215     private void processInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
216         List<FlowEntity> addFlowEntries = new ArrayList<>();
217         List<FlowEntity> deleteFlowEntries = new ArrayList<>();
218         List<AllowedAddressPairs> addedAaps = AclServiceUtils
219                 .getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
220         List<AllowedAddressPairs> deletedAaps = AclServiceUtils
221                 .getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
222         if (!deletedAaps.isEmpty()) {
223             programAclWithAllowedAddress(deleteFlowEntries, portBefore, deletedAaps, Action.UPDATE,
224                     NwConstants.DEL_FLOW);
225             updateRemoteAclFilterTable(deleteFlowEntries, portBefore, portBefore.getSecurityGroups(), deletedAaps,
226                     NwConstants.DEL_FLOW);
227         }
228         if (!addedAaps.isEmpty()) {
229             programAclWithAllowedAddress(addFlowEntries, portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
230             updateRemoteAclFilterTable(addFlowEntries, portAfter, portAfter.getSecurityGroups(), addedAaps,
231                     NwConstants.ADD_FLOW);
232         }
233         if (portAfter.getSubnetInfo() != null && portBefore.getSubnetInfo() == null) {
234             programBroadcastRules(addFlowEntries, portAfter, Action.UPDATE, NwConstants.ADD_FLOW);
235         }
236         handleSubnetChange(portBefore, portAfter, addFlowEntries, deleteFlowEntries);
237
238         List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter.getSecurityGroups(),
239                 portBefore.getSecurityGroups());
240         List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore.getSecurityGroups(),
241                 portAfter.getSecurityGroups());
242         if (!deletedAcls.isEmpty() || !addedAcls.isEmpty()) {
243             handleAclChange(deleteFlowEntries, portBefore, deletedAcls, NwConstants.DEL_FLOW);
244             handleAclChange(addFlowEntries, portAfter, addedAcls, NwConstants.ADD_FLOW);
245         }
246
247         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), deleteFlowEntries,
248                 NwConstants.DEL_FLOW);
249         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), addFlowEntries,
250                 NwConstants.ADD_FLOW);
251     }
252
253     private void handleSubnetChange(AclInterface portBefore, AclInterface portAfter,
254             List<FlowEntity> addFlowEntries, List<FlowEntity> deleteFlowEntries) {
255         List<SubnetInfo> deletedSubnets =
256                 AclServiceUtils.getSubnetDiff(portBefore.getSubnetInfo(), portAfter.getSubnetInfo());
257         List<SubnetInfo> addedSubnets =
258                 AclServiceUtils.getSubnetDiff(portAfter.getSubnetInfo(), portBefore.getSubnetInfo());
259
260         if (deletedSubnets != null && !deletedSubnets.isEmpty()) {
261             programIcmpv6RARule(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
262             programSubnetBroadcastRules(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
263         }
264         if (addedSubnets != null && !addedSubnets.isEmpty()) {
265             programIcmpv6RARule(addFlowEntries, portAfter, addedSubnets, NwConstants.ADD_FLOW);
266             programSubnetBroadcastRules(addFlowEntries, portAfter, addedSubnets, NwConstants.ADD_FLOW);
267         }
268     }
269
270     private void handleAclChange(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclList,
271             int addOrRemove) {
272         int operationForAclRules = addOrRemove == NwConstants.DEL_FLOW ? NwConstants.MOD_FLOW : addOrRemove;
273         programAclRules(flowEntries, port, aclList, operationForAclRules);
274         updateRemoteAclFilterTable(flowEntries, port, aclList, port.getAllowedAddressPairs(), addOrRemove);
275         programAclDispatcherTable(flowEntries, port, addOrRemove);
276     }
277
278     protected SortedSet<Integer> getRemoteAclTags(AclInterface port) {
279         return this.direction == DirectionIngress.class ? port.getIngressRemoteAclTags()
280                 : port.getEgressRemoteAclTags();
281     }
282
283     protected void programAclDispatcherTable(List<FlowEntity> flowEntries, AclInterface port, int addOrRemove) {
284         SortedSet<Integer> remoteAclTags = getRemoteAclTags(port);
285         if (remoteAclTags.isEmpty()) {
286             LOG.debug("No {} rules with remote group id for port={}", this.directionString, port.getInterfaceId());
287             return;
288         }
289         Integer firstRemoteAclTag = remoteAclTags.first();
290         Integer lastRemoteAclTag = remoteAclTags.last();
291
292         programFirstRemoteAclEntryInDispatcherTable(flowEntries, port, firstRemoteAclTag, addOrRemove);
293         programLastRemoteAclEntryInDispatcherTable(flowEntries, port, lastRemoteAclTag, addOrRemove);
294
295         Integer previousRemoteAclTag = firstRemoteAclTag;
296         for (Integer remoteAclTag : remoteAclTags) {
297             if (remoteAclTag.equals(firstRemoteAclTag)) {
298                 continue;
299             }
300             List<MatchInfoBase> matches = new ArrayList<>();
301             matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(),
302                     previousRemoteAclTag, serviceMode));
303             String flowId = this.directionString + "_ACL_Dispatcher_" + port.getDpId() + "_" + port.getLPortTag() + "_"
304                     + remoteAclTag;
305
306             List<InstructionInfo> instructions =
307                     AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
308             instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(remoteAclTag));
309             addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
310                     AclConstants.ACE_GOTO_NEXT_REMOTE_ACL_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
311                     instructions, addOrRemove);
312
313             previousRemoteAclTag = remoteAclTag;
314         }
315     }
316
317     protected void programFirstRemoteAclEntryInDispatcherTable(List<FlowEntity> flowEntries, AclInterface port,
318             Integer firstRemoteAclTag, int addOrRemove) {
319         List<MatchInfoBase> matches = new ArrayList<>();
320         matches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
321         String flowId = this.directionString + "_ACL_Dispatcher_First_" + port.getDpId() + "_" + port.getLPortTag()
322                 + "_" + firstRemoteAclTag;
323
324         List<InstructionInfo> instructions =
325                 AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
326         instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(firstRemoteAclTag));
327         addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
328                 AclConstants.ACE_FIRST_REMOTE_ACL_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
329                 addOrRemove);
330     }
331
332     protected void programLastRemoteAclEntryInDispatcherTable(List<FlowEntity> flowEntries, AclInterface port,
333             Integer lastRemoteAclTag, int addOrRemove) {
334         List<MatchInfoBase> matches = new ArrayList<>();
335         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(), lastRemoteAclTag,
336                 serviceMode));
337         String flowId = this.directionString + "_ACL_Dispatcher_Last_" + port.getDpId() + "_" + port.getLPortTag() + "_"
338                 + lastRemoteAclTag;
339
340         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
341         addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
342                 AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(port.getLPortTag()),
343                 matches, instructions, addOrRemove);
344     }
345
346     private void programAcl(List<FlowEntity> flowEntries, AclInterface port, Action action, int addOrRemove) {
347         programAclWithAllowedAddress(flowEntries, port, port.getAllowedAddressPairs(), action, addOrRemove);
348     }
349
350     private void programAclWithAllowedAddress(List<FlowEntity> flowEntries, AclInterface port,
351             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
352         Uint64 dpId = Uint64.valueOf(port.getDpId());
353         int lportTag = port.getLPortTag();
354         LOG.debug("Applying ACL Allowed Address on DpId {}, lportTag {}, Action {}", dpId, lportTag, action);
355         String portId = port.getInterfaceId();
356         programAntiSpoofingRules(flowEntries, port, allowedAddresses, action, addOrRemove);
357         programAclPortSpecificFixedRules(flowEntries, dpId, allowedAddresses, lportTag, portId, action, addOrRemove);
358         if (action == Action.ADD || action == Action.REMOVE) {
359             programAclRules(flowEntries, port, port.getSecurityGroups(), addOrRemove);
360             programAclDispatcherTable(flowEntries, port, addOrRemove);
361         }
362     }
363
364     /**
365      * Programs the acl custom rules.
366      *
367      * @param flowEntries the flow entries
368      * @param port acl interface
369      * @param aclUuidList the list of acl uuid to be applied
370      * @param addOrRemove whether to delete or add flow
371      * @return program succeeded
372      */
373     protected boolean programAclRules(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclUuidList,
374             int addOrRemove) {
375         BigInteger dpId = port.getDpId();
376         LOG.debug("Applying custom rules on DpId {}, lportTag {}", dpId, port.getLPortTag());
377         if (aclUuidList == null || dpId == null) {
378             LOG.warn("{} ACL parameters can not be null. dpId={}, aclUuidList={}", this.directionString, dpId,
379                     aclUuidList);
380             return false;
381         }
382         for (Uuid aclUuid : aclUuidList) {
383             Acl acl = this.aclDataUtil.getAcl(aclUuid.getValue());
384             if (null == acl) {
385                 LOG.warn("The ACL {} not found in cache", aclUuid.getValue());
386                 continue;
387             }
388             for (Ace ace : AclServiceUtils.aceList(acl)) {
389                 programAceRule(flowEntries, port, aclUuid.getValue(), ace, addOrRemove);
390             }
391         }
392         return true;
393     }
394
395     /**
396      * Programs the ace specific rule.
397      *
398      * @param flowEntries flow entries
399      * @param port acl interface
400      * @param aclName the acl name
401      * @param ace rule to be program
402      * @param addOrRemove whether to delete or add flow
403      */
404     protected void programAceRule(List<FlowEntity> flowEntries, AclInterface port, String aclName, Ace ace,
405             int addOrRemove) {
406         SecurityRuleAttr aceAttr = AclServiceUtils.getAccessListAttributes(ace);
407         if (aceAttr == null) {
408             LOG.error("Ace {} of Acl {} is either null or not having SecurityRuleAttr",
409                     ace == null ? null : ace.getRuleName(), aclName);
410             return;
411         }
412         if (addOrRemove == NwConstants.ADD_FLOW && aceAttr.isDeleted()) {
413             LOG.trace("Ignoring {} rule which is already deleted", ace.getRuleName());
414             return;
415         }
416         if (!isValidDirection(aceAttr.getDirection())) {
417             LOG.trace("Ignoring {} direction while processing for {} ACE Rule {}", aceAttr.getDirection(),
418                     this.directionString, ace.getRuleName());
419             return;
420         }
421         LOG.debug("Program {} ACE rule for dpId={}, lportTag={}, addOrRemove={}, ace={}, portId={}",
422                 this.directionString, port.getDpId(), port.getLPortTag(), addOrRemove, ace.getRuleName(),
423                 port.getInterfaceId());
424
425         Matches matches = ace.getMatches();
426         if (matches != null && matches.getAceType() instanceof AceIp) {
427             Map<String, List<MatchInfoBase>> flowMap = AclServiceOFFlowBuilder.programIpFlow(matches);
428             if (!AclServiceUtils.doesAceHaveRemoteGroupId(aceAttr)) {
429                 // programming for ACE which doesn't have any remote group Id
430                 programForAceNotHavingRemoteAclId(flowEntries, port, aclName, ace, flowMap, addOrRemove);
431             } else {
432                 Uuid remoteAclId = aceAttr.getRemoteGroupId();
433                 // programming for ACE which have remote group Id
434                 programAceSpecificFlows(flowEntries, port, aclName, ace, flowMap, remoteAclId, addOrRemove);
435             }
436         }
437     }
438
439     protected void programForAceNotHavingRemoteAclId(List<FlowEntity> flowEntries, AclInterface port, String aclName,
440             Ace ace, @Nullable Map<String, List<MatchInfoBase>> flowMap, int addOrRemove) {
441         if (null == flowMap) {
442             return;
443         }
444         MatchInfoBase lportTagMatch = AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode);
445         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
446         Integer flowPriority = this.aclServiceUtils.getAceFlowPriority(aclName);
447
448         for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
449             String flowName = entry.getKey();
450             List<MatchInfoBase> matches = entry.getValue();
451             matches.add(lportTagMatch);
452             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
453                     + ace.key().getRuleName();
454
455             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
456             addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(),
457                     flowId, flowPriority, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
458
459             if (addOrRemove != NwConstants.DEL_FLOW) {
460                 programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
461             }
462         }
463     }
464
465     protected void programAceSpecificFlows(List<FlowEntity> flowEntries, AclInterface port, String aclName, Ace ace,
466             @Nullable Map<String, List<MatchInfoBase>> flowMap, Uuid remoteAclId, int addOrRemove) {
467         if (null == flowMap) {
468             return;
469         }
470         Integer remoteAclTag = this.aclServiceUtils.getAclTag(remoteAclId);
471         if (remoteAclTag == null || remoteAclTag == AclConstants.INVALID_ACL_TAG) {
472             LOG.error("remoteAclTag={} is null or invalid for remoteAclId={}", remoteAclTag, remoteAclId);
473             return;
474         }
475         List<MatchInfoBase> lportAndAclMatches =
476                 AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(), remoteAclTag, serviceMode);
477         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRemoteAclTable());
478         Integer flowPriority = this.aclServiceUtils.getAceFlowPriority(aclName);
479
480         for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
481             String flowName = entry.getKey();
482             List<MatchInfoBase> matches = entry.getValue();
483             matches.addAll(lportAndAclMatches);
484             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
485                     + ace.key().getRuleName();
486
487             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
488             addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclRuleBasedFilterTable(), flowId,
489                     flowPriority, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
490
491             if (addOrRemove != NwConstants.DEL_FLOW) {
492                 programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
493             }
494         }
495     }
496
497     private void programAclForExistingTrafficTable(AclInterface port, Ace ace, int addOrRemove, String flowName,
498             List<MatchInfoBase> matches, Integer priority) {
499         if (port == null || port.getElanId() == null) {
500             LOG.debug("Acl interface or elan id is null, No need to update traffic flow table.");
501             return;
502         }
503
504         AceIp acl = (AceIp) ace.getMatches().getAceType();
505         final String newFlowName = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag()
506                 + "_" + (acl.getAceIpVersion() instanceof AceIpv4 ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
507
508         final List<MatchInfoBase> newMatches =
509                 matches.stream().filter(obj -> !(obj instanceof NxMatchCtState || obj instanceof MatchMetadata))
510                         .collect(Collectors.toList());
511         newMatches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
512         newMatches.add(new NxMatchCtState(AclConstants.TRACKED_RPL_CT_STATE, AclConstants.TRACKED_RPL_CT_STATE_MASK));
513
514         List<InstructionInfo> instructions =
515                 AclServiceUtils.createCtMarkInstructionForNewState(getAclFilterCumDispatcherTable(), port.getElanId());
516         // Reversing the flow add/delete operation for this table.
517         List<FlowEntity> flowEntries = new ArrayList<>();
518         int operation = addOrRemove == NwConstants.ADD_FLOW ? NwConstants.DEL_FLOW : NwConstants.ADD_FLOW;
519         addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclForExistingTrafficTable(), newFlowName,
520                 priority, 0, AclServiceUtils.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
521                 AclConstants.COOKIE_ACL_BASE, newMatches, instructions, operation);
522         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, operation);
523     }
524
525     @Override
526     public boolean removeAcl(AclInterface port) {
527         if (port.getDpId() == null) {
528             LOG.warn("Unable to find DP Id from ACL interface with id {}", port.getInterfaceId());
529             return false;
530         }
531         List<FlowEntity> flowEntries = new ArrayList<>();
532         if (port.getInterfaceType() == InterfaceType.DhcpService) {
533             programDhcpService(flowEntries, port, Action.REMOVE, NwConstants.DEL_FLOW);
534         } else {
535             programAcl(flowEntries, port, Action.REMOVE, NwConstants.DEL_FLOW);
536             updateRemoteAclFilterTable(flowEntries, port, NwConstants.DEL_FLOW);
537         }
538         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
539         return true;
540     }
541
542     @Override
543     public boolean applyAce(AclInterface port, String aclName, Ace ace) {
544         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
545             return false;
546         }
547         List<FlowEntity> flowEntries = new ArrayList<>();
548         programAceRule(flowEntries, port, aclName, ace, NwConstants.ADD_FLOW);
549         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.ADD_FLOW);
550         return true;
551     }
552
553     @Override
554     public boolean removeAce(AclInterface port, String aclName, Ace ace) {
555         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
556             return false;
557         }
558         List<FlowEntity> flowEntries = new ArrayList<>();
559         programAceRule(flowEntries, port, aclName, ace, NwConstants.MOD_FLOW);
560         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
561         return true;
562     }
563
564     @Override
565     public void updateRemoteAcl(Acl aclBefore, Acl aclAfter, Collection<AclInterface> portsBefore) {
566         handleRemoteAclUpdate(aclBefore, aclAfter, portsBefore);
567     }
568
569     /**
570      * Bind service.
571      *
572      * @param aclInterface the acl interface
573      */
574     public abstract void bindService(AclInterface aclInterface);
575
576     /**
577      * Unbind service.
578      *
579      * @param aclInterface the acl interface
580      */
581     protected abstract void unbindService(AclInterface aclInterface);
582
583     /**
584      * Programs DHCP Service flows.
585      *
586      * @param flowEntries the flow entries
587      * @param port the acl interface
588      * @param action add/modify/remove action
589      * @param addOrRemove addorRemove
590      */
591     protected abstract void programDhcpService(List<FlowEntity> flowEntries, AclInterface port,
592             Action action, int addOrRemove);
593
594     /**
595      * Programs DHCP service flows.
596      *
597      * @param flowEntries the flow entries
598      * @param port the acl interface
599      * @param allowedAddresses the allowed addresses
600      * @param addOrRemove addorRemove
601      */
602     protected abstract void processDhcpServiceUpdate(List<FlowEntity> flowEntries, AclInterface port,
603             List<AllowedAddressPairs> allowedAddresses, int addOrRemove);
604
605     /**
606      * Programs the anti-spoofing rules.
607      *
608      * @param flowEntries the flow entries
609      * @param port the acl interface
610      * @param allowedAddresses the allowed addresses
611      * @param action add/modify/remove action
612      * @param addOrRemove addorRemove
613      */
614     protected abstract void programAntiSpoofingRules(List<FlowEntity> flowEntries, AclInterface port,
615             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove);
616
617     /**
618      * Programs broadcast rules.
619      *
620      * @param flowEntries the flow entries
621      * @param port the Acl Interface port
622      * @param addOrRemove whether to delete or add flow
623      */
624     protected abstract void programBroadcastRules(List<FlowEntity> flowEntries, AclInterface port, Action action,
625             int addOrRemove);
626
627     /**
628      * Programs broadcast rules.
629      *
630      * @param flowEntries the flow entries
631      * @param port the Acl Interface port
632      * @param subnetInfoList the port subnet info list
633      * @param addOrRemove whether to delete or add flow
634      */
635     protected abstract void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
636             List<SubnetInfo> subnetInfoList, int addOrRemove);
637
638     protected abstract void programIcmpv6RARule(List<FlowEntity> flowEntries, AclInterface port,
639             List<SubnetInfo> subnets, int addOrRemove);
640
641     /**
642      * Add Flow to list.
643      *
644      * @param dpId
645      *            the dpId
646      * @param tableId
647      *            the tableId
648      * @param flowId
649      *            the flowId
650      * @param priority
651      *            the priority
652      * @param idleTimeOut
653      *            the idle timeout
654      * @param hardTimeOut
655      *            the hard timeout
656      * @param cookie
657      *            the cookie
658      * @param matches
659      *            the list of matches to be writted
660      * @param instructions
661      *            the list of instruction to be written.
662      * @param addOrRemove
663      *            add or remove the entries.
664      */
665     protected void addFlowEntryToList(List<FlowEntity> flowEntries, Uint64 dpId, short tableId, String flowId,
666             int priority, int idleTimeOut, int hardTimeOut, Uint64 cookie, List<? extends MatchInfoBase> matches,
667             List<InstructionInfo> instructions, int addOrRemove) {
668         List<InstructionInfo> instructionInfos = null;
669         if (addOrRemove == NwConstants.ADD_FLOW) {
670             instructionInfos = instructions;
671         }
672         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority,
673                 flowId, idleTimeOut, hardTimeOut, cookie, matches, instructionInfos);
674         LOG.trace("Adding flow to list: DpnId {}, flowId {}", dpId, flowId);
675         flowEntries.add(flowEntity);
676     }
677
678     protected void programFlows(String jobName, List<FlowEntity> flowEntries, int addOrRemove) {
679         List<List<FlowEntity>> flowEntityParts = Lists.partition(flowEntries, AclConstants.FLOWS_PER_TRANSACTION);
680         for (List<FlowEntity> part : flowEntityParts) {
681             jobCoordinator.enqueueJob(jobName,
682                 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
683                     tx -> {
684                         if (addOrRemove == NwConstants.ADD_FLOW) {
685                             for (FlowEntity flowEntity: part) {
686                                 mdsalManager.addFlow(tx, flowEntity);
687                             }
688                         } else {
689                             for (FlowEntity flowEntity: part) {
690                                 mdsalManager.removeFlow(tx, flowEntity);
691                             }
692                         }
693                     })), AclConstants.JOB_MAX_RETRIES);
694         }
695     }
696
697     protected List<InstructionInfo> getDispatcherTableResubmitInstructions() {
698         return getDispatcherTableResubmitInstructions(new ArrayList<>());
699     }
700
701     /**
702      * Gets the dispatcher table resubmit instructions based on ingress/egress service mode w.r.t switch.
703      *
704      * @param actionsInfos
705      *            the actions infos
706      * @return the instructions for dispatcher table resubmit
707      */
708     protected List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos) {
709         short dispatcherTableId = NwConstants.LPORT_DISPATCHER_TABLE;
710         if (ServiceModeEgress.class.equals(this.serviceMode)) {
711             dispatcherTableId = NwConstants.EGRESS_LPORT_DISPATCHER_TABLE;
712         }
713
714         List<InstructionInfo> instructions = new ArrayList<>();
715         actionsInfos.add(new ActionNxResubmit(dispatcherTableId));
716         instructions.add(new InstructionApplyActions(actionsInfos));
717         return instructions;
718     }
719
720     protected void handleRemoteAclUpdate(Acl aclBefore, Acl aclAfter, Collection<AclInterface> portsBefore) {
721         String aclName = aclAfter.getAclName();
722         Collection<AclInterface> interfaceList = aclDataUtil.getInterfaceList(new Uuid(aclName));
723         if (interfaceList.isEmpty()) {
724             LOG.trace("handleRemoteAclUpdate: No interfaces found with ACL={}", aclName);
725             return;
726         }
727         Set<Uuid> remoteAclsBefore = AclServiceUtils.getRemoteAclIdsByDirection(aclBefore, this.direction);
728         Set<Uuid> remoteAclsAfter = AclServiceUtils.getRemoteAclIdsByDirection(aclAfter, this.direction);
729
730         Set<Uuid> remoteAclsAdded = new HashSet<>(remoteAclsAfter);
731         remoteAclsAdded.removeAll(remoteAclsBefore);
732
733         Set<Uuid> remoteAclsDeleted = new HashSet<>(remoteAclsBefore);
734         remoteAclsDeleted.removeAll(remoteAclsAfter);
735
736         List<FlowEntity> addFlowEntries = new ArrayList<>();
737         List<FlowEntity> deleteFlowEntries = new ArrayList<>();
738         if (!remoteAclsAdded.isEmpty() || !remoteAclsDeleted.isEmpty()) {
739             // delete and add flows in ACL dispatcher table for all applicable
740             // ports
741             for (AclInterface portBefore : portsBefore) {
742                 programAclDispatcherTable(deleteFlowEntries, portBefore, NwConstants.DEL_FLOW);
743             }
744             for (AclInterface port : interfaceList) {
745                 programAclDispatcherTable(addFlowEntries, port, NwConstants.ADD_FLOW);
746             }
747         }
748         Set<BigInteger> dpns = interfaceList.stream().map(AclInterface::getDpId).collect(Collectors.toSet());
749
750         programRemoteAclTable(deleteFlowEntries, aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
751         programRemoteAclTable(addFlowEntries, aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
752
753         programFlows(aclName, deleteFlowEntries, NwConstants.DEL_FLOW);
754         programFlows(aclName, addFlowEntries, NwConstants.ADD_FLOW);
755     }
756
757     private void programRemoteAclTable(List<FlowEntity> flowEntries, String aclName, Set<Uuid> remoteAclIds,
758             Set<BigInteger> dpns, int addOrRemove) {
759         for (Uuid remoteAclId : remoteAclIds) {
760             Collection<AclInterface> remoteAclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
761             if (remoteAclInterfaces.isEmpty()) {
762                 continue;
763             }
764             Set<AllowedAddressPairs> aaps =
765                     remoteAclInterfaces.stream().map(AclInterface::getAllowedAddressPairs).flatMap(List::stream)
766                             .filter(AclServiceUtils::isNotIpAllNetwork).collect(Collectors.toSet());
767
768             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
769             if (addOrRemove == NwConstants.ADD_FLOW) {
770                 for (BigInteger dpn : dpns) {
771                     for (AllowedAddressPairs aap : aaps) {
772                         programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpn), aclTag, aap, addOrRemove);
773                     }
774                 }
775             } else if (addOrRemove == NwConstants.DEL_FLOW) {
776                 Set<BigInteger> remoteAclDpns = new HashSet<>();
777                 Map<String, Set<AclInterface>> mapAclWithPortSet =
778                         aclDataUtil.getRemoteAclInterfaces(remoteAclId, this.direction);
779                 if (mapAclWithPortSet != null) {
780                     Map<String, Set<AclInterface>> copyOfMapAclWithPortSet = new HashMap<>(mapAclWithPortSet);
781                     copyOfMapAclWithPortSet.remove(aclName);
782                     remoteAclDpns = collectDpns(copyOfMapAclWithPortSet);
783                 }
784                 Set<BigInteger> dpnsToOperate = new HashSet<>(dpns);
785                 dpnsToOperate.removeAll(remoteAclDpns);
786                 LOG.debug(
787                         "Deleting flows in Remote ACL table for remoteAclId={}, direction={}, dpnsToOperate={}, "
788                                 + "remoteAclDpns={}, dpns={}",
789                         remoteAclId.getValue(), directionString, dpnsToOperate, remoteAclDpns, dpns);
790
791                 for (BigInteger dpn : dpnsToOperate) {
792                     for (AllowedAddressPairs aap : aaps) {
793                         programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpn), aclTag, aap, addOrRemove);
794                     }
795                 }
796             }
797         }
798     }
799
800     private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, int addOrRemove) {
801         updateRemoteAclFilterTable(flowEntries, port, port.getSecurityGroups(), port.getAllowedAddressPairs(),
802                 addOrRemove);
803     }
804
805     private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclList,
806             List<AllowedAddressPairs> aaps, int addOrRemove) {
807         if (aclList == null) {
808             LOG.debug("Port {} without SGs", port.getInterfaceId());
809             return;
810         }
811         String portId = port.getInterfaceId();
812         LOG.trace("updateRemoteAclFilterTable for portId={}, aclList={}, aaps={}, addOrRemove={}", portId, aclList,
813                 aaps, addOrRemove);
814         for (Uuid aclId : aclList) {
815             if (aclDataUtil.getRemoteAcl(aclId, this.direction) != null) {
816                 Integer aclTag = aclServiceUtils.getAclTag(aclId);
817                 if (addOrRemove == NwConstants.ADD_FLOW) {
818                     syncRemoteAclTable(flowEntries, portId, aclId, aclTag, aaps, addOrRemove);
819                 }
820                 else if (addOrRemove == NwConstants.DEL_FLOW) {
821                     jobCoordinator.enqueueJob(aclId.getValue(), () -> {
822                         List<FlowEntity> remoteTableFlowEntries = new ArrayList<>();
823                         syncRemoteAclTable(remoteTableFlowEntries, portId, aclId, aclTag, aaps, addOrRemove);
824                         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + aclId.getValue(),
825                                 remoteTableFlowEntries, NwConstants.DEL_FLOW);
826                         return Collections.emptyList();
827                     });
828                 }
829             }
830         }
831         Set<Uuid> remoteAclIds = aclServiceUtils.getRemoteAclIdsByDirection(aclList, direction);
832         for (Uuid remoteAclId : remoteAclIds) {
833             syncRemoteAclTableFromOtherDpns(flowEntries, port, remoteAclId, addOrRemove);
834         }
835     }
836
837     private void syncRemoteAclTable(List<FlowEntity> flowEntries, String portId, Uuid acl, Integer aclTag,
838             List<AllowedAddressPairs> aaps, int addOrRemove) {
839         Map<String, Set<AclInterface>> mapAclWithPortSet = aclDataUtil.getRemoteAclInterfaces(acl, this.direction);
840         Set<BigInteger> dpns = collectDpns(mapAclWithPortSet);
841         for (AllowedAddressPairs aap : aaps) {
842             if (!AclServiceUtils.isNotIpAllNetwork(aap)) {
843                 continue;
844             }
845             if (aclServiceUtils.skipDeleteInCaseOfOverlappingIP(portId, acl, aap.getIpAddress(),
846                     addOrRemove)) {
847                 LOG.debug("Skipping delete of IP={} in remote ACL table for remoteAclId={}, portId={}",
848                         aap.getIpAddress(), portId, acl.getValue());
849                 continue;
850             }
851             for (BigInteger dpId : dpns) {
852                 programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpId), aclTag, aap, addOrRemove);
853             }
854         }
855     }
856
857     private void syncRemoteAclTableFromOtherDpns(List<FlowEntity> flowEntries, AclInterface port, Uuid remoteAclId,
858             int addOrRemove) {
859         Collection<AclInterface> aclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
860
861         if (!aclInterfaces.isEmpty() && isFirstPortInDpnWithRemoteAclId(port, remoteAclId)) {
862             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
863             for (AclInterface aclInterface : aclInterfaces) {
864                 if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
865                     continue;
866                 }
867                 for (AllowedAddressPairs aap : aclInterface.getAllowedAddressPairs()) {
868                     if (AclServiceUtils.isNotIpAllNetwork(aap)) {
869                         programRemoteAclTableFlow(flowEntries, Uint64.valueOf(port.getDpId()),
870                             aclTag, aap, addOrRemove);
871                     }
872                 }
873             }
874         }
875     }
876
877     private boolean isFirstPortInDpnWithRemoteAclId(AclInterface port, Uuid remoteAclId) {
878         String portId = port.getInterfaceId();
879         BigInteger dpId = port.getDpId();
880         Map<String, Set<AclInterface>> remoteAclInterfacesMap =
881                 aclDataUtil.getRemoteAclInterfaces(remoteAclId, direction);
882         if (remoteAclInterfacesMap != null) {
883             for (Set<AclInterface> interfaceSet : remoteAclInterfacesMap.values()) {
884                 for (AclInterface aclInterface : interfaceSet) {
885                     if (portId.equals(aclInterface.getInterfaceId())) {
886                         continue;
887                     }
888                     if (dpId.equals(aclInterface.getDpId())) {
889                         return false;
890                     }
891                 }
892             }
893         }
894         return true;
895     }
896
897     protected abstract void programRemoteAclTableFlow(List<FlowEntity> flowEntries, Uint64 dpId, Integer aclTag,
898             AllowedAddressPairs aap, int addOrRemove);
899
900     protected Set<BigInteger> collectDpns(@Nullable Map<String, Set<AclInterface>> mapAclWithPortSet) {
901         Set<BigInteger> dpns = new HashSet<>();
902         if (mapAclWithPortSet == null) {
903             return dpns;
904         }
905         for (Set<AclInterface> innerSet : mapAclWithPortSet.values()) {
906             if (innerSet == null) {
907                 continue;
908             }
909             for (AclInterface inter : innerSet) {
910                 dpns.add(inter.getDpId());
911             }
912         }
913         return dpns;
914     }
915
916     /**
917      * Programs the port specific fixed rules.
918      *
919      * @param flowEntries the flow entries
920      * @param dpId the dp id
921      * @param allowedAddresses the allowed addresses
922      * @param lportTag the lport tag
923      * @param portId the portId
924      * @param action the action
925      * @param write whether to add or remove the flow.
926      */
927     protected void programAclPortSpecificFixedRules(List<FlowEntity> flowEntries, Uint64 dpId,
928             List<AllowedAddressPairs> allowedAddresses, int lportTag, String portId, Action action, int write) {
929         programGotoClassifierTableRules(flowEntries, dpId, allowedAddresses, lportTag, write);
930         if (action == Action.ADD || action == Action.REMOVE) {
931             programConntrackRecircRules(flowEntries, dpId, allowedAddresses, lportTag, portId, write);
932             programPortSpecificDropRules(flowEntries, dpId, lportTag, write);
933             programAclCommitRules(flowEntries, dpId, lportTag, portId, write);
934         }
935         LOG.info("programAclPortSpecificFixedRules: flows for dpId={}, lportId={}, action={}, write={}", dpId, lportTag,
936                 action, write);
937     }
938
939     protected abstract void programGotoClassifierTableRules(List<FlowEntity> flowEntries, Uint64 dpId,
940             List<AllowedAddressPairs> aaps, int lportTag, int addOrRemove);
941
942     /**
943      * Adds the rule to send the packet to the netfilter to check whether it is a known packet.
944      *
945      * @param flowEntries the flow entries
946      * @param dpId the dpId
947      * @param aaps the allowed address pairs
948      * @param lportTag the lport tag
949      * @param portId the portId
950      * @param addOrRemove whether to add or remove the flow
951      */
952     protected void programConntrackRecircRules(List<FlowEntity> flowEntries, Uint64 dpId,
953             List<AllowedAddressPairs> aaps, int lportTag, String portId, int addOrRemove) {
954         if (AclServiceUtils.doesIpv4AddressExists(aaps)) {
955             programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
956         }
957         if (AclServiceUtils.doesIpv6AddressExists(aaps)) {
958             programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
959         }
960     }
961
962     protected void programConntrackRecircRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
963             String portId, MatchEthernetType matchEtherType, int addOrRemove) {
964         List<MatchInfoBase> matches = new ArrayList<>();
965         matches.add(matchEtherType);
966         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
967
968         List<InstructionInfo> instructions = new ArrayList<>();
969         if (addOrRemove == NwConstants.ADD_FLOW) {
970             Long elanTag = getElanIdFromAclInterface(portId);
971             if (elanTag == null) {
972                 LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={},", portId,
973                         dpId, lportTag, addOrRemove);
974                 return;
975             }
976             List<ActionInfo> actionsInfos = new ArrayList<>();
977             actionsInfos.add(new ActionNxConntrack(2, 0, 0, elanTag.intValue(), getAclForExistingTrafficTable()));
978             instructions.add(new InstructionApplyActions(actionsInfos));
979         }
980
981         String flowName =
982                 this.directionString + "_Fixed_Conntrk_" + dpId.toString() + "_"
983                     + lportTag + "_" + matchEtherType + "_Recirc";
984         addFlowEntryToList(flowEntries, dpId, getAclConntrackSenderTable(), flowName,
985                 AclConstants.ACL_DEFAULT_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
986                 addOrRemove);
987     }
988
989     /**
990      * Adds the rules to drop the unknown/invalid packets .
991      *
992      * @param flowEntries the flow entries
993      * @param dpId the dpId
994      * @param lportTag the lport tag
995      * @param addOrRemove whether to add or remove the flow
996      */
997     protected void programPortSpecificDropRules(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
998             int addOrRemove) {
999         LOG.debug("Programming Drop Rules: DpId={}, lportTag={}, addOrRemove={}", dpId, lportTag, addOrRemove);
1000         programConntrackInvalidDropRule(flowEntries, dpId, lportTag, addOrRemove);
1001         programAclRuleMissDropRule(flowEntries, dpId, lportTag, addOrRemove);
1002     }
1003
1004     /**
1005      * Adds the rule to drop the conntrack invalid packets .
1006      *
1007      * @param flowEntries the flow entries
1008      * @param dpId the dpId
1009      * @param lportTag the lport tag
1010      * @param addOrRemove whether to add or remove the flow
1011      */
1012     protected void programConntrackInvalidDropRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
1013             int addOrRemove) {
1014         List<MatchInfoBase> matches = AclServiceOFFlowBuilder.addLPortTagMatches(lportTag,
1015                 AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, serviceMode);
1016         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
1017
1018         String flowId = this.directionString + "_Fixed_Conntrk_Drop" + dpId.toString()
1019                             + "_" + lportTag + "_Tracked_Invalid";
1020         addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
1021                 AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
1022                 matches, instructions, addOrRemove);
1023     }
1024
1025     /**
1026      * Program ACL rule miss drop rule for a port.
1027      *
1028      * @param flowEntries the flow entries
1029      * @param dpId the dp id
1030      * @param lportTag the lport tag
1031      * @param addOrRemove the add or remove
1032      */
1033     protected void programAclRuleMissDropRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
1034             int addOrRemove) {
1035         List<MatchInfoBase> matches = new ArrayList<>();
1036         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
1037         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
1038
1039         String flowId = this.directionString + "_Fixed_Acl_Rule_Miss_Drop_" + dpId.toString() + "_" + lportTag;
1040         addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
1041                 AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
1042                 matches, instructions, addOrRemove);
1043     }
1044
1045     /**
1046      * Program acl commit rules.
1047      *
1048      * @param flowEntries the flow entries
1049      * @param dpId the dp id
1050      * @param lportTag the lport tag
1051      * @param portId the port id
1052      * @param addOrRemove the add or remove
1053      */
1054     protected void programAclCommitRules(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag, String portId,
1055             int addOrRemove) {
1056         programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
1057         programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
1058         programAclCommitRuleForNonConntrack(flowEntries, dpId, lportTag, addOrRemove);
1059     }
1060
1061     /**
1062      * Program acl commit rule for conntrack.
1063      *
1064      * @param flowEntries the flow entries
1065      * @param dpId the dp id
1066      * @param lportTag the lport tag
1067      * @param portId the port id
1068      * @param matchEtherType the match ether type
1069      * @param addOrRemove the add or remove
1070      */
1071     protected void programAclCommitRuleForConntrack(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
1072             String portId, MatchEthernetType matchEtherType, int addOrRemove) {
1073         List<MatchInfoBase> matches = new ArrayList<>();
1074         matches.add(matchEtherType);
1075         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
1076                 AclConntrackClassifierType.CONNTRACK_SUPPORTED, serviceMode));
1077
1078         List<ActionInfo> actionsInfos = new ArrayList<>();
1079         if (addOrRemove == NwConstants.ADD_FLOW) {
1080             Long elanId = getElanIdFromAclInterface(portId);
1081             if (elanId == null) {
1082                 LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={}", portId, dpId,
1083                         lportTag, addOrRemove);
1084                 return;
1085             }
1086             List<NxCtAction> ctActionsList =
1087                     Lists.newArrayList(new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_EST_STATE));
1088             actionsInfos.add(new ActionNxConntrack(2, 1, 0, elanId.intValue(), (short) 255, ctActionsList));
1089             actionsInfos.add(new ActionNxCtClear());
1090         }
1091         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
1092
1093         String flowName = directionString + "_Acl_Commit_Conntrack_" + dpId.toString()
1094                             + "_" + lportTag + "_" + matchEtherType;
1095         // Flow for conntrack traffic to commit and resubmit to dispatcher
1096         addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
1097                 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
1098     }
1099
1100     /**
1101      * Program acl commit rule for non conntrack.
1102      *
1103      * @param flowEntries the flow entries
1104      * @param dpId the dp id
1105      * @param lportTag the lport tag
1106      * @param addOrRemove the add or remove
1107      */
1108     protected void programAclCommitRuleForNonConntrack(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
1109             int addOrRemove) {
1110         List<MatchInfoBase> matches = new ArrayList<>();
1111         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
1112                 AclConntrackClassifierType.NON_CONNTRACK_SUPPORTED, serviceMode));
1113
1114         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
1115         String flowName = this.directionString + "_Acl_Commit_Non_Conntrack_" + dpId + "_" + lportTag;
1116         // Flow for non-conntrack traffic to resubmit to dispatcher
1117         addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
1118                 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
1119     }
1120
1121     @Nullable
1122     protected Long getElanIdFromAclInterface(String elanInterfaceName) {
1123         AclInterface aclInterface = aclInterfaceCache.get(elanInterfaceName);
1124         if (null != aclInterface) {
1125             return aclInterface.getElanId();
1126         }
1127         return null;
1128     }
1129
1130     protected abstract boolean isValidDirection(Class<? extends DirectionBase> direction);
1131
1132     protected abstract short getAclConntrackSenderTable();
1133
1134     protected abstract short getAclForExistingTrafficTable();
1135
1136     protected abstract short getAclFilterCumDispatcherTable();
1137
1138     protected abstract short getAclRuleBasedFilterTable();
1139
1140     protected abstract short getAclRemoteAclTable();
1141
1142     protected abstract short getAclCommitterTable();
1143 }