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