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