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