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