3b78577f1c6f8cc046c461b53478508d0d3cdd2d
[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 (addOrRemove == NwConstants.ADD_FLOW && aceAttr.isDeleted()) {
384             LOG.trace("Ignoring {} rule which is already deleted", ace.getRuleName());
385             return;
386         }
387         if (!isValidDirection(aceAttr.getDirection())) {
388             LOG.trace("Ignoring {} direction while processing for {} ACE Rule {}", aceAttr.getDirection(),
389                     this.directionString, ace.getRuleName());
390             return;
391         }
392         LOG.debug("Program {} ACE rule for dpId={}, lportTag={}, addOrRemove={}, ace={}, portId={}",
393                 this.directionString, port.getDpId(), port.getLPortTag(), addOrRemove, ace.getRuleName(),
394                 port.getInterfaceId());
395
396         Matches matches = ace.getMatches();
397         if (matches != null && matches.getAceType() instanceof AceIp) {
398             Map<String, List<MatchInfoBase>> flowMap = AclServiceOFFlowBuilder.programIpFlow(matches);
399             if (!AclServiceUtils.doesAceHaveRemoteGroupId(aceAttr)) {
400                 // programming for ACE which doesn't have any remote group Id
401                 programForAceNotHavingRemoteAclId(flowEntries, port, aclName, ace, flowMap, addOrRemove);
402             } else {
403                 Uuid remoteAclId = aceAttr.getRemoteGroupId();
404                 // programming for ACE which have remote group Id
405                 programAceSpecificFlows(flowEntries, port, aclName, ace, flowMap, remoteAclId, addOrRemove);
406             }
407         }
408     }
409
410     protected void programForAceNotHavingRemoteAclId(List<FlowEntity> flowEntries, AclInterface port, String aclName,
411             Ace ace, @Nullable Map<String, List<MatchInfoBase>> flowMap, int addOrRemove) {
412         if (null == flowMap) {
413             return;
414         }
415         MatchInfoBase lportTagMatch = AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode);
416         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
417         Integer flowPriority = this.aclServiceUtils.getAceFlowPriority(aclName);
418
419         for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
420             String flowName = entry.getKey();
421             List<MatchInfoBase> matches = entry.getValue();
422             matches.add(lportTagMatch);
423             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
424                     + ace.key().getRuleName();
425
426             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
427             addFlowEntryToList(flowEntries, port.getDpId(), getAclFilterCumDispatcherTable(), flowId, flowPriority,
428                     0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
429
430             if (addOrRemove != NwConstants.DEL_FLOW) {
431                 programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
432             }
433         }
434     }
435
436     protected void programAceSpecificFlows(List<FlowEntity> flowEntries, AclInterface port, String aclName, Ace ace,
437             @Nullable Map<String, List<MatchInfoBase>> flowMap, Uuid remoteAclId, int addOrRemove) {
438         if (null == flowMap) {
439             return;
440         }
441         Integer remoteAclTag = this.aclServiceUtils.getAclTag(remoteAclId);
442         if (remoteAclTag == null || remoteAclTag == AclConstants.INVALID_ACL_TAG) {
443             LOG.error("remoteAclTag={} is null or invalid for remoteAclId={}", remoteAclTag, remoteAclId);
444             return;
445         }
446         List<MatchInfoBase> lportAndAclMatches =
447                 AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(), remoteAclTag, serviceMode);
448         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRemoteAclTable());
449         Integer flowPriority = this.aclServiceUtils.getAceFlowPriority(aclName);
450
451         for (Entry<String, List<MatchInfoBase>> entry : flowMap.entrySet()) {
452             String flowName = entry.getKey();
453             List<MatchInfoBase> matches = entry.getValue();
454             matches.addAll(lportAndAclMatches);
455             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
456                     + ace.key().getRuleName();
457
458             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
459             addFlowEntryToList(flowEntries, port.getDpId(), getAclRuleBasedFilterTable(), flowId, flowPriority, 0, 0,
460                     AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
461
462             if (addOrRemove != NwConstants.DEL_FLOW) {
463                 programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
464             }
465         }
466     }
467
468     private void programAclForExistingTrafficTable(AclInterface port, Ace ace, int addOrRemove, String flowName,
469             List<MatchInfoBase> matches, Integer priority) {
470         AceIp acl = (AceIp) ace.getMatches().getAceType();
471         final String newFlowName = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag()
472                 + "_" + (acl.getAceIpVersion() instanceof AceIpv4 ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
473
474         final List<MatchInfoBase> newMatches =
475                 matches.stream().filter(obj -> !(obj instanceof NxMatchCtState || obj instanceof MatchMetadata))
476                         .collect(Collectors.toList());
477         newMatches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
478         newMatches.add(new NxMatchCtState(AclConstants.TRACKED_RPL_CT_STATE, AclConstants.TRACKED_RPL_CT_STATE_MASK));
479
480         List<InstructionInfo> instructions =
481                 AclServiceUtils.createCtMarkInstructionForNewState(getAclFilterCumDispatcherTable(), port.getElanId());
482         // Reversing the flow add/delete operation for this table.
483         List<FlowEntity> flowEntries = new ArrayList<>();
484         int operation = addOrRemove == NwConstants.ADD_FLOW ? NwConstants.DEL_FLOW : NwConstants.ADD_FLOW;
485         addFlowEntryToList(flowEntries, port.getDpId(), getAclForExistingTrafficTable(), newFlowName, priority, 0,
486                 AclServiceUtils.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
487                 AclConstants.COOKIE_ACL_BASE, newMatches, instructions, operation);
488         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, operation);
489     }
490
491     @Override
492     public boolean removeAcl(AclInterface port) {
493         if (port.getDpId() == null) {
494             LOG.warn("Unable to find DP Id from ACL interface with id {}", port.getInterfaceId());
495             return false;
496         }
497         List<FlowEntity> flowEntries = new ArrayList<>();
498         programAcl(flowEntries, port, Action.REMOVE, NwConstants.DEL_FLOW);
499         updateRemoteAclFilterTable(flowEntries, port, NwConstants.DEL_FLOW);
500         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
501         return true;
502     }
503
504     @Override
505     public boolean applyAce(AclInterface port, String aclName, Ace ace) {
506         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
507             return false;
508         }
509         List<FlowEntity> flowEntries = new ArrayList<>();
510         programAceRule(flowEntries, port, aclName, ace, NwConstants.ADD_FLOW);
511         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.ADD_FLOW);
512         return true;
513     }
514
515     @Override
516     public boolean removeAce(AclInterface port, String aclName, Ace ace) {
517         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
518             return false;
519         }
520         List<FlowEntity> flowEntries = new ArrayList<>();
521         programAceRule(flowEntries, port, aclName, ace, NwConstants.MOD_FLOW);
522         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
523         return true;
524     }
525
526     @Override
527     public void updateRemoteAcl(Acl aclBefore, Acl aclAfter, Collection<AclInterface> portsBefore) {
528         handleRemoteAclUpdate(aclBefore, aclAfter, portsBefore);
529     }
530
531     /**
532      * Bind service.
533      *
534      * @param aclInterface the acl interface
535      */
536     public abstract void bindService(AclInterface aclInterface);
537
538     /**
539      * Unbind service.
540      *
541      * @param aclInterface the acl interface
542      */
543     protected abstract void unbindService(AclInterface aclInterface);
544
545     /**
546      * Programs the anti-spoofing rules.
547      *
548      * @param flowEntries the flow entries
549      * @param port the acl interface
550      * @param allowedAddresses the allowed addresses
551      * @param action add/modify/remove action
552      * @param addOrRemove addorRemove
553      */
554     protected abstract void programAntiSpoofingRules(List<FlowEntity> flowEntries, AclInterface port,
555             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove);
556
557     /**
558      * Programs broadcast rules.
559      *
560      * @param flowEntries the flow entries
561      * @param port the Acl Interface port
562      * @param addOrRemove whether to delete or add flow
563      */
564     protected abstract void programBroadcastRules(List<FlowEntity> flowEntries, AclInterface port, Action action,
565             int addOrRemove);
566
567     /**
568      * Programs broadcast rules.
569      *
570      * @param flowEntries the flow entries
571      * @param port the Acl Interface port
572      * @param subnetInfoList the port subnet info list
573      * @param addOrRemove whether to delete or add flow
574      */
575     protected abstract void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
576             List<SubnetInfo> subnetInfoList, int addOrRemove);
577
578     protected abstract void programIcmpv6RARule(List<FlowEntity> flowEntries, AclInterface port,
579             List<SubnetInfo> subnets, int addOrRemove);
580
581     /**
582      * Add Flow to list.
583      *
584      * @param dpId
585      *            the dpId
586      * @param tableId
587      *            the tableId
588      * @param flowId
589      *            the flowId
590      * @param priority
591      *            the priority
592      * @param idleTimeOut
593      *            the idle timeout
594      * @param hardTimeOut
595      *            the hard timeout
596      * @param cookie
597      *            the cookie
598      * @param matches
599      *            the list of matches to be writted
600      * @param instructions
601      *            the list of instruction to be written.
602      * @param addOrRemove
603      *            add or remove the entries.
604      */
605     protected void addFlowEntryToList(List<FlowEntity> flowEntries, BigInteger dpId, short tableId, String flowId,
606             int priority, int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase> matches,
607             List<InstructionInfo> instructions, int addOrRemove) {
608         List<InstructionInfo> instructionInfos = null;
609         if (addOrRemove == NwConstants.ADD_FLOW) {
610             instructionInfos = instructions;
611         }
612         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority,
613                 flowId, idleTimeOut, hardTimeOut, cookie, matches, instructionInfos);
614         LOG.trace("Adding flow to list: DpnId {}, flowId {}", dpId, flowId);
615         flowEntries.add(flowEntity);
616     }
617
618     protected void programFlows(String jobName, List<FlowEntity> flowEntries, int addOrRemove) {
619         List<List<FlowEntity>> flowEntityParts = Lists.partition(flowEntries, AclConstants.FLOWS_PER_TRANSACTION);
620         for (List<FlowEntity> part : flowEntityParts) {
621             jobCoordinator.enqueueJob(jobName,
622                 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
623                     tx -> {
624                         if (addOrRemove == NwConstants.ADD_FLOW) {
625                             for (FlowEntity flowEntity: part) {
626                                 mdsalManager.addFlow(tx, flowEntity);
627                             }
628                         } else {
629                             for (FlowEntity flowEntity: part) {
630                                 mdsalManager.removeFlow(tx, flowEntity);
631                             }
632                         }
633                     })), AclConstants.JOB_MAX_RETRIES);
634         }
635     }
636
637     protected List<InstructionInfo> getDispatcherTableResubmitInstructions() {
638         return getDispatcherTableResubmitInstructions(new ArrayList<>());
639     }
640
641     /**
642      * Gets the dispatcher table resubmit instructions based on ingress/egress service mode w.r.t switch.
643      *
644      * @param actionsInfos
645      *            the actions infos
646      * @return the instructions for dispatcher table resubmit
647      */
648     protected List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos) {
649         short dispatcherTableId = NwConstants.LPORT_DISPATCHER_TABLE;
650         if (ServiceModeEgress.class.equals(this.serviceMode)) {
651             dispatcherTableId = NwConstants.EGRESS_LPORT_DISPATCHER_TABLE;
652         }
653
654         List<InstructionInfo> instructions = new ArrayList<>();
655         actionsInfos.add(new ActionNxResubmit(dispatcherTableId));
656         instructions.add(new InstructionApplyActions(actionsInfos));
657         return instructions;
658     }
659
660     protected void handleRemoteAclUpdate(Acl aclBefore, Acl aclAfter, Collection<AclInterface> portsBefore) {
661         String aclName = aclAfter.getAclName();
662         Collection<AclInterface> interfaceList = aclDataUtil.getInterfaceList(new Uuid(aclName));
663         if (interfaceList.isEmpty()) {
664             LOG.trace("handleRemoteAclUpdate: No interfaces found with ACL={}", aclName);
665             return;
666         }
667         Set<Uuid> remoteAclsBefore = AclServiceUtils.getRemoteAclIdsByDirection(aclBefore, this.direction);
668         Set<Uuid> remoteAclsAfter = AclServiceUtils.getRemoteAclIdsByDirection(aclAfter, this.direction);
669
670         Set<Uuid> remoteAclsAdded = new HashSet<>(remoteAclsAfter);
671         remoteAclsAdded.removeAll(remoteAclsBefore);
672
673         Set<Uuid> remoteAclsDeleted = new HashSet<>(remoteAclsBefore);
674         remoteAclsDeleted.removeAll(remoteAclsAfter);
675
676         List<FlowEntity> addFlowEntries = new ArrayList<>();
677         List<FlowEntity> deleteFlowEntries = new ArrayList<>();
678         if (!remoteAclsAdded.isEmpty() || !remoteAclsDeleted.isEmpty()) {
679             // delete and add flows in ACL dispatcher table for all applicable
680             // ports
681             for (AclInterface portBefore : portsBefore) {
682                 programAclDispatcherTable(deleteFlowEntries, portBefore, NwConstants.DEL_FLOW);
683             }
684             for (AclInterface port : interfaceList) {
685                 programAclDispatcherTable(addFlowEntries, port, NwConstants.ADD_FLOW);
686             }
687         }
688         Set<BigInteger> dpns = interfaceList.stream().map(AclInterface::getDpId).collect(Collectors.toSet());
689
690         programRemoteAclTable(deleteFlowEntries, aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
691         programRemoteAclTable(addFlowEntries, aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
692
693         programFlows(aclName, deleteFlowEntries, NwConstants.DEL_FLOW);
694         programFlows(aclName, addFlowEntries, NwConstants.ADD_FLOW);
695     }
696
697     private void programRemoteAclTable(List<FlowEntity> flowEntries, String aclName, Set<Uuid> remoteAclIds,
698             Set<BigInteger> dpns, int addOrRemove) {
699         for (Uuid remoteAclId : remoteAclIds) {
700             Collection<AclInterface> remoteAclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
701             if (remoteAclInterfaces.isEmpty()) {
702                 continue;
703             }
704             Set<AllowedAddressPairs> aaps =
705                     remoteAclInterfaces.stream().map(AclInterface::getAllowedAddressPairs).flatMap(List::stream)
706                             .filter(AclServiceUtils::isNotIpAllNetwork).collect(Collectors.toSet());
707
708             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
709             if (addOrRemove == NwConstants.ADD_FLOW) {
710                 for (BigInteger dpn : dpns) {
711                     for (AllowedAddressPairs aap : aaps) {
712                         programRemoteAclTableFlow(flowEntries, dpn, aclTag, aap, addOrRemove);
713                     }
714                 }
715             } else if (addOrRemove == NwConstants.DEL_FLOW) {
716                 Set<BigInteger> remoteAclDpns = new HashSet<>();
717                 Map<String, Set<AclInterface>> mapAclWithPortSet =
718                         aclDataUtil.getRemoteAclInterfaces(remoteAclId, this.direction);
719                 if (mapAclWithPortSet != null) {
720                     Map<String, Set<AclInterface>> copyOfMapAclWithPortSet = new HashMap<>(mapAclWithPortSet);
721                     copyOfMapAclWithPortSet.remove(aclName);
722                     remoteAclDpns = collectDpns(copyOfMapAclWithPortSet);
723                 }
724                 Set<BigInteger> dpnsToOperate = new HashSet<>(dpns);
725                 dpnsToOperate.removeAll(remoteAclDpns);
726                 LOG.debug(
727                         "Deleting flows in Remote ACL table for remoteAclId={}, direction={}, dpnsToOperate={}, "
728                                 + "remoteAclDpns={}, dpns={}",
729                         remoteAclId.getValue(), directionString, dpnsToOperate, remoteAclDpns, dpns);
730
731                 for (BigInteger dpn : dpnsToOperate) {
732                     for (AllowedAddressPairs aap : aaps) {
733                         programRemoteAclTableFlow(flowEntries, dpn, aclTag, aap, addOrRemove);
734                     }
735                 }
736             }
737         }
738     }
739
740     private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, int addOrRemove) {
741         updateRemoteAclFilterTable(flowEntries, port, port.getSecurityGroups(), port.getAllowedAddressPairs(),
742                 addOrRemove);
743     }
744
745     private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclList,
746             List<AllowedAddressPairs> aaps, int addOrRemove) {
747         if (aclList == null) {
748             LOG.debug("Port {} without SGs", port.getInterfaceId());
749             return;
750         }
751         String portId = port.getInterfaceId();
752         LOG.trace("updateRemoteAclFilterTable for portId={}, aclList={}, aaps={}, addOrRemove={}", portId, aclList,
753                 aaps, addOrRemove);
754         for (Uuid aclId : aclList) {
755             if (aclDataUtil.getRemoteAcl(aclId, this.direction) != null) {
756                 Integer aclTag = aclServiceUtils.getAclTag(aclId);
757                 if (addOrRemove == NwConstants.ADD_FLOW) {
758                     syncRemoteAclTable(flowEntries, portId, aclId, aclTag, aaps, addOrRemove);
759                 }
760                 else if (addOrRemove == NwConstants.DEL_FLOW) {
761                     jobCoordinator.enqueueJob(aclId.getValue(), () -> {
762                         List<FlowEntity> remoteTableFlowEntries = new ArrayList<>();
763                         syncRemoteAclTable(remoteTableFlowEntries, portId, aclId, aclTag, aaps, addOrRemove);
764                         programFlows(AclConstants.ACL_JOB_KEY_PREFIX + aclId.getValue(),
765                                 remoteTableFlowEntries, NwConstants.DEL_FLOW);
766                         return Collections.emptyList();
767                     });
768                 }
769             }
770         }
771         Set<Uuid> remoteAclIds = aclServiceUtils.getRemoteAclIdsByDirection(aclList, direction);
772         for (Uuid remoteAclId : remoteAclIds) {
773             syncRemoteAclTableFromOtherDpns(flowEntries, port, remoteAclId, addOrRemove);
774         }
775     }
776
777     private void syncRemoteAclTable(List<FlowEntity> flowEntries, String portId, Uuid acl, Integer aclTag,
778             List<AllowedAddressPairs> aaps, int addOrRemove) {
779         Map<String, Set<AclInterface>> mapAclWithPortSet = aclDataUtil.getRemoteAclInterfaces(acl, this.direction);
780         Set<BigInteger> dpns = collectDpns(mapAclWithPortSet);
781         for (AllowedAddressPairs aap : aaps) {
782             if (!AclServiceUtils.isNotIpAllNetwork(aap)) {
783                 continue;
784             }
785             if (aclServiceUtils.skipDeleteInCaseOfOverlappingIP(portId, acl, aap.getIpAddress(),
786                     addOrRemove)) {
787                 LOG.debug("Skipping delete of IP={} in remote ACL table for remoteAclId={}, portId={}",
788                         aap.getIpAddress(), portId, acl.getValue());
789                 continue;
790             }
791             for (BigInteger dpId : dpns) {
792                 programRemoteAclTableFlow(flowEntries, dpId, aclTag, aap, addOrRemove);
793             }
794         }
795     }
796
797     private void syncRemoteAclTableFromOtherDpns(List<FlowEntity> flowEntries, AclInterface port, Uuid remoteAclId,
798             int addOrRemove) {
799         Collection<AclInterface> aclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
800
801         if (!aclInterfaces.isEmpty() && isFirstPortInDpnWithRemoteAclId(port, remoteAclId)) {
802             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
803             for (AclInterface aclInterface : aclInterfaces) {
804                 if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
805                     continue;
806                 }
807                 for (AllowedAddressPairs aap : aclInterface.getAllowedAddressPairs()) {
808                     if (AclServiceUtils.isNotIpAllNetwork(aap)) {
809                         programRemoteAclTableFlow(flowEntries, port.getDpId(), aclTag, aap, addOrRemove);
810                     }
811                 }
812             }
813         }
814     }
815
816     private boolean isFirstPortInDpnWithRemoteAclId(AclInterface port, Uuid remoteAclId) {
817         String portId = port.getInterfaceId();
818         BigInteger dpId = port.getDpId();
819         Map<String, Set<AclInterface>> remoteAclInterfacesMap =
820                 aclDataUtil.getRemoteAclInterfaces(remoteAclId, direction);
821         if (remoteAclInterfacesMap != null) {
822             for (Set<AclInterface> interfaceSet : remoteAclInterfacesMap.values()) {
823                 for (AclInterface aclInterface : interfaceSet) {
824                     if (portId.equals(aclInterface.getInterfaceId())) {
825                         continue;
826                     }
827                     if (dpId.equals(aclInterface.getDpId())) {
828                         return false;
829                     }
830                 }
831             }
832         }
833         return true;
834     }
835
836     protected abstract void programRemoteAclTableFlow(List<FlowEntity> flowEntries, BigInteger dpId, Integer aclTag,
837             AllowedAddressPairs aap, int addOrRemove);
838
839     protected Set<BigInteger> collectDpns(@Nullable Map<String, Set<AclInterface>> mapAclWithPortSet) {
840         Set<BigInteger> dpns = new HashSet<>();
841         if (mapAclWithPortSet == null) {
842             return dpns;
843         }
844         for (Set<AclInterface> innerSet : mapAclWithPortSet.values()) {
845             if (innerSet == null) {
846                 continue;
847             }
848             for (AclInterface inter : innerSet) {
849                 dpns.add(inter.getDpId());
850             }
851         }
852         return dpns;
853     }
854
855     /**
856      * Programs the port specific fixed rules.
857      *
858      * @param flowEntries the flow entries
859      * @param dpId the dp id
860      * @param allowedAddresses the allowed addresses
861      * @param lportTag the lport tag
862      * @param portId the portId
863      * @param action the action
864      * @param write whether to add or remove the flow.
865      */
866     protected void programAclPortSpecificFixedRules(List<FlowEntity> flowEntries, BigInteger dpId,
867             List<AllowedAddressPairs> allowedAddresses, int lportTag, String portId, Action action, int write) {
868         programGotoClassifierTableRules(flowEntries, dpId, allowedAddresses, lportTag, write);
869         if (action == Action.ADD || action == Action.REMOVE) {
870             programConntrackRecircRules(flowEntries, dpId, allowedAddresses, lportTag, portId, write);
871             programPortSpecificDropRules(flowEntries, dpId, lportTag, write);
872             programAclCommitRules(flowEntries, dpId, lportTag, portId, write);
873         }
874         LOG.info("programAclPortSpecificFixedRules: flows for dpId={}, lportId={}, action={}, write={}", dpId, lportTag,
875                 action, write);
876     }
877
878     protected abstract void programGotoClassifierTableRules(List<FlowEntity> flowEntries, BigInteger dpId,
879             List<AllowedAddressPairs> aaps, int lportTag, int addOrRemove);
880
881     /**
882      * Adds the rule to send the packet to the netfilter to check whether it is a known packet.
883      *
884      * @param flowEntries the flow entries
885      * @param dpId the dpId
886      * @param aaps the allowed address pairs
887      * @param lportTag the lport tag
888      * @param portId the portId
889      * @param addOrRemove whether to add or remove the flow
890      */
891     protected void programConntrackRecircRules(List<FlowEntity> flowEntries, BigInteger dpId,
892             List<AllowedAddressPairs> aaps, int lportTag, String portId, int addOrRemove) {
893         if (AclServiceUtils.doesIpv4AddressExists(aaps)) {
894             programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
895         }
896         if (AclServiceUtils.doesIpv6AddressExists(aaps)) {
897             programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
898         }
899     }
900
901     protected void programConntrackRecircRule(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
902             String portId, MatchEthernetType matchEtherType, int addOrRemove) {
903         List<MatchInfoBase> matches = new ArrayList<>();
904         matches.add(matchEtherType);
905         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
906
907         List<InstructionInfo> instructions = new ArrayList<>();
908         if (addOrRemove == NwConstants.ADD_FLOW) {
909             Long elanTag = getElanIdFromAclInterface(portId);
910             if (elanTag == null) {
911                 LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={},", portId,
912                         dpId, lportTag, addOrRemove);
913                 return;
914             }
915             List<ActionInfo> actionsInfos = new ArrayList<>();
916             actionsInfos.add(new ActionNxConntrack(2, 0, 0, elanTag.intValue(), getAclForExistingTrafficTable()));
917             instructions.add(new InstructionApplyActions(actionsInfos));
918         }
919
920         String flowName =
921                 this.directionString + "_Fixed_Conntrk_" + dpId + "_" + lportTag + "_" + matchEtherType + "_Recirc";
922         addFlowEntryToList(flowEntries, dpId, getAclConntrackSenderTable(), flowName,
923                 AclConstants.ACL_DEFAULT_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
924                 addOrRemove);
925     }
926
927     /**
928      * Adds the rules to drop the unknown/invalid packets .
929      *
930      * @param flowEntries the flow entries
931      * @param dpId the dpId
932      * @param lportTag the lport tag
933      * @param addOrRemove whether to add or remove the flow
934      */
935     protected void programPortSpecificDropRules(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
936             int addOrRemove) {
937         LOG.debug("Programming Drop Rules: DpId={}, lportTag={}, addOrRemove={}", dpId, lportTag, addOrRemove);
938         programConntrackInvalidDropRule(flowEntries, dpId, lportTag, addOrRemove);
939         programAclRuleMissDropRule(flowEntries, dpId, lportTag, addOrRemove);
940     }
941
942     /**
943      * Adds the rule to drop the conntrack invalid packets .
944      *
945      * @param flowEntries the flow entries
946      * @param dpId the dpId
947      * @param lportTag the lport tag
948      * @param addOrRemove whether to add or remove the flow
949      */
950     protected void programConntrackInvalidDropRule(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
951             int addOrRemove) {
952         List<MatchInfoBase> matches = AclServiceOFFlowBuilder.addLPortTagMatches(lportTag,
953                 AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, serviceMode);
954         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
955
956         String flowId = this.directionString + "_Fixed_Conntrk_Drop" + dpId + "_" + lportTag + "_Tracked_Invalid";
957         addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
958                 AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
959                 matches, instructions, addOrRemove);
960     }
961
962     /**
963      * Program ACL rule miss drop rule for a port.
964      *
965      * @param flowEntries the flow entries
966      * @param dpId the dp id
967      * @param lportTag the lport tag
968      * @param addOrRemove the add or remove
969      */
970     protected void programAclRuleMissDropRule(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
971             int addOrRemove) {
972         List<MatchInfoBase> matches = new ArrayList<>();
973         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
974         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
975
976         String flowId = this.directionString + "_Fixed_Acl_Rule_Miss_Drop_" + dpId + "_" + lportTag;
977         addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
978                 AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
979                 matches, instructions, addOrRemove);
980     }
981
982     /**
983      * Program acl commit rules.
984      *
985      * @param flowEntries the flow entries
986      * @param dpId the dp id
987      * @param lportTag the lport tag
988      * @param portId the port id
989      * @param addOrRemove the add or remove
990      */
991     protected void programAclCommitRules(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag, String portId,
992             int addOrRemove) {
993         programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
994         programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
995         programAclCommitRuleForNonConntrack(flowEntries, dpId, lportTag, addOrRemove);
996     }
997
998     /**
999      * Program acl commit rule for conntrack.
1000      *
1001      * @param flowEntries the flow entries
1002      * @param dpId the dp id
1003      * @param lportTag the lport tag
1004      * @param portId the port id
1005      * @param matchEtherType the match ether type
1006      * @param addOrRemove the add or remove
1007      */
1008     protected void programAclCommitRuleForConntrack(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
1009             String portId, MatchEthernetType matchEtherType, int addOrRemove) {
1010         List<MatchInfoBase> matches = new ArrayList<>();
1011         matches.add(matchEtherType);
1012         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
1013                 AclConntrackClassifierType.CONNTRACK_SUPPORTED, serviceMode));
1014
1015         List<ActionInfo> actionsInfos = new ArrayList<>();
1016         if (addOrRemove == NwConstants.ADD_FLOW) {
1017             Long elanId = getElanIdFromAclInterface(portId);
1018             if (elanId == null) {
1019                 LOG.error("ElanId not found for portId={}; Context: dpId={}, lportTag={}, addOrRemove={}", portId, dpId,
1020                         lportTag, addOrRemove);
1021                 return;
1022             }
1023             List<NxCtAction> ctActionsList =
1024                     Lists.newArrayList(new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_EST_STATE));
1025             actionsInfos.add(new ActionNxConntrack(2, 1, 0, elanId.intValue(), (short) 255, ctActionsList));
1026             actionsInfos.add(new ActionNxCtClear());
1027         }
1028         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
1029
1030         String flowName = directionString + "_Acl_Commit_Conntrack_" + dpId + "_" + lportTag + "_" + matchEtherType;
1031         // Flow for conntrack traffic to commit and resubmit to dispatcher
1032         addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
1033                 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
1034     }
1035
1036     /**
1037      * Program acl commit rule for non conntrack.
1038      *
1039      * @param flowEntries the flow entries
1040      * @param dpId the dp id
1041      * @param lportTag the lport tag
1042      * @param addOrRemove the add or remove
1043      */
1044     protected void programAclCommitRuleForNonConntrack(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
1045             int addOrRemove) {
1046         List<MatchInfoBase> matches = new ArrayList<>();
1047         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
1048                 AclConntrackClassifierType.NON_CONNTRACK_SUPPORTED, serviceMode));
1049
1050         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
1051         String flowName = this.directionString + "_Acl_Commit_Non_Conntrack_" + dpId + "_" + lportTag;
1052         // Flow for non-conntrack traffic to resubmit to dispatcher
1053         addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
1054                 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
1055     }
1056
1057     @Nullable
1058     protected Long getElanIdFromAclInterface(String elanInterfaceName) {
1059         AclInterface aclInterface = aclInterfaceCache.get(elanInterfaceName);
1060         if (null != aclInterface) {
1061             return aclInterface.getElanId();
1062         }
1063         return null;
1064     }
1065
1066     protected abstract boolean isValidDirection(Class<? extends DirectionBase> direction);
1067
1068     protected abstract short getAclConntrackSenderTable();
1069
1070     protected abstract short getAclForExistingTrafficTable();
1071
1072     protected abstract short getAclFilterCumDispatcherTable();
1073
1074     protected abstract short getAclRuleBasedFilterTable();
1075
1076     protected abstract short getAclRemoteAclTable();
1077
1078     protected abstract short getAclCommitterTable();
1079 }