6ea8ce0e0627b36601614179c5308e69d4b63ce7
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / IngressAclServiceImpl.java
1 /*
2  * Copyright (c) 2018 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.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12
13 import com.google.common.collect.Lists;
14
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.genius.mdsalutil.FlowEntity;
21 import org.opendaylight.genius.mdsalutil.InstructionInfo;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.MatchInfo;
24 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
25 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
26 import org.opendaylight.genius.mdsalutil.NwConstants;
27 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
28 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
29 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
30 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
31 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv4;
32 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
33 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
34 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
35 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
36 import org.opendaylight.genius.utils.ServiceIndex;
37 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
38 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
39 import org.opendaylight.netvirt.aclservice.api.AclServiceManager;
40 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
41 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
42 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
43 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
44 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
45 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
46 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefixBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl.InterfaceType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.SubnetInfo;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 /**
64  * Provides the implementation for ingress (w.r.t VM) ACL service.
65  *
66  * <p>
67  * Note: Table names used are w.r.t switch. Hence, switch ingress is VM egress
68  * and vice versa.
69  */
70 public class IngressAclServiceImpl extends AbstractAclServiceImpl {
71
72     private static final Logger LOG = LoggerFactory.getLogger(IngressAclServiceImpl.class);
73
74     /**
75      * Initialize the member variables.
76      *
77      * @param dataBroker the data broker instance.
78      * @param mdsalManager the mdsal manager.
79      * @param aclDataUtil the acl data util.
80      * @param aclServiceUtils the acl service util.
81      * @param jobCoordinator the job coordinator
82      * @param aclInterfaceCache the acl interface cache
83      */
84     public IngressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
85             AclServiceUtils aclServiceUtils, JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
86         // Service mode is w.rt. switch
87         super(ServiceModeEgress.class, dataBroker, mdsalManager, aclDataUtil, aclServiceUtils, jobCoordinator,
88                 aclInterfaceCache);
89     }
90
91     /**
92      * Bind service.
93      *
94      * @param aclInterface the acl interface
95      */
96     @Override
97     public void bindService(AclInterface aclInterface) {
98         String interfaceName = aclInterface.getInterfaceId();
99         jobCoordinator.enqueueJob(interfaceName, () -> {
100             int instructionKey = 0;
101             List<Instruction> instructions = new ArrayList<>();
102             instructions.add(
103                     MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.EGRESS_ACL_DUMMY_TABLE, ++instructionKey));
104             int flowPriority = NwConstants.EGRESS_ACL_SERVICE_INDEX;
105             short serviceIndex =
106                     ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX);
107             BoundServices serviceInfo =
108                     AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "acl", "egressacl", interfaceName),
109                             serviceIndex, flowPriority, AclConstants.COOKIE_ACL_BASE, instructions);
110             InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
111                     ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
112                     serviceMode);
113
114             return Collections.singletonList(
115                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.put(
116                             path, serviceInfo, CREATE_MISSING_PARENTS)));
117         });
118     }
119
120     /**
121      * Unbind service.
122      *
123      * @param aclInterface the acl interface
124      */
125     @Override
126     protected void unbindService(AclInterface aclInterface) {
127         String interfaceName = aclInterface.getInterfaceId();
128         InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
129                 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
130                 serviceMode);
131
132         LOG.debug("UnBinding ACL service for interface {}", interfaceName);
133         jobCoordinator.enqueueJob(interfaceName, () -> Collections.singletonList(txRunner
134                 .callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(path))));
135     }
136
137     /**
138      * Programs DHCP Service flows.
139      *
140      * @param flowEntries the flow entries
141      * @param port the acl interface
142      * @param action add/modify/remove action
143      * @param addOrRemove addorRemove
144      */
145     @Override
146     protected void programDhcpService(List<FlowEntity> flowEntries, AclInterface port,
147             Action action, int addOrRemove) {
148         LOG.info("{} programDhcpService for port {}, action={}, addOrRemove={}", this.directionString,
149                 port.getInterfaceId(), action, addOrRemove);
150         BigInteger dpid = port.getDpId();
151         int lportTag = port.getLPortTag();
152         allowDhcpClientTraffic(flowEntries, dpid, lportTag, addOrRemove);
153         allowDhcpv6ClientTraffic(flowEntries, dpid, lportTag, addOrRemove);
154         programArpRule(flowEntries, dpid, lportTag, addOrRemove);
155         ingressAclIcmpv6AllowedTraffic(flowEntries, port, InterfaceType.DhcpService, addOrRemove);
156         allowIcmpTrafficToDhcpServer(flowEntries, port, port.getAllowedAddressPairs(), addOrRemove);
157         dropTrafficToDhcpServer(flowEntries, dpid, lportTag, addOrRemove);
158         programCommitterDropFlow(flowEntries, dpid, lportTag, addOrRemove);
159     }
160
161     /**
162      * Programs DHCP service flows.
163      *
164      * @param flowEntries the flow entries
165      * @param port the acl interface
166      * @param allowedAddresses the allowed addresses
167      * @param addOrRemove addorRemove
168      */
169     @Override
170     protected void processDhcpServiceUpdate(List<FlowEntity> flowEntries, AclInterface port,
171             List<AllowedAddressPairs> allowedAddresses, int addOrRemove) {
172         allowIcmpTrafficToDhcpServer(flowEntries, port, allowedAddresses, addOrRemove);
173     }
174
175     @Override
176     protected void programAntiSpoofingRules(List<FlowEntity> flowEntries, AclInterface port,
177             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
178         LOG.info("{} programAntiSpoofingRules for port {}, AAPs={}, action={}, addOrRemove={}", this.directionString,
179                 port.getInterfaceId(), allowedAddresses, action, addOrRemove);
180
181         BigInteger dpid = port.getDpId();
182         int lportTag = port.getLPortTag();
183         if (action == Action.ADD || action == Action.REMOVE) {
184             programCommitterDropFlow(flowEntries, dpid, lportTag, addOrRemove);
185             ingressAclDhcpAllowServerTraffic(flowEntries, dpid, lportTag, addOrRemove);
186             ingressAclDhcpv6AllowServerTraffic(flowEntries, dpid, lportTag, addOrRemove);
187             ingressAclIcmpv6AllowedTraffic(flowEntries, port, InterfaceType.AccessPort, addOrRemove);
188             programIcmpv6RARule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
189
190             programArpRule(flowEntries, dpid, lportTag, addOrRemove);
191             programIpv4BroadcastRule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
192         }
193     }
194
195     private void programCommitterDropFlow(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
196             int addOrRemove) {
197         List<MatchInfoBase> matches = new ArrayList<>();
198         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
199
200         BigInteger metaData = MetaDataUtil.METADATA_MASK_ACL_DROP
201                 .and(AclConstants.METADATA_DROP_FLAG.shiftLeft(2));
202         BigInteger metaDataMask = MetaDataUtil.METADATA_MASK_ACL_DROP
203                 .and(AclConstants.METADATA_DROP_FLAG.shiftLeft(2));
204         matches.add(new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
205                 MetaDataUtil.getLportTagMaskForReg6()));
206         matches.add(new MatchMetadata(metaData, metaDataMask));
207
208         String flowName = "Ingress_" + dpId + "_" + lportTag + "_Drop";
209         addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName,
210                 AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
211                 matches, instructions, addOrRemove);
212     }
213
214     @Override
215     protected void programGotoClassifierTableRules(List<FlowEntity> flowEntries, BigInteger dpId,
216             List<AllowedAddressPairs> aaps, int lportTag, int addOrRemove) {
217         for (AllowedAddressPairs aap : aaps) {
218             IpPrefixOrAddress attachIp = aap.getIpAddress();
219             MacAddress mac = aap.getMacAddress();
220
221             List<MatchInfoBase> matches = new ArrayList<>();
222             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
223             matches.add(new MatchEthernetDestination(mac));
224             matches.addAll(AclServiceUtils.buildIpMatches(attachIp, MatchCriteria.MATCH_DESTINATION));
225
226             List<InstructionInfo> gotoInstructions = new ArrayList<>();
227             gotoInstructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
228
229             String flowName = "Ingress_Fixed_Goto_Classifier_" + dpId + "_" + lportTag + "_" + mac.getValue() + "_"
230                     + attachIp.stringValue();
231             addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
232                     AclConstants.PROTO_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, gotoInstructions,
233                     addOrRemove);
234         }
235     }
236
237     @Override
238     protected void programRemoteAclTableFlow(List<FlowEntity> flowEntries, BigInteger dpId, Integer aclTag,
239             AllowedAddressPairs aap, int addOrRemove) {
240         List<MatchInfoBase> flowMatches = new ArrayList<>();
241         flowMatches.addAll(AclServiceUtils.buildIpAndSrcServiceMatch(aclTag, aap));
242
243         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
244         String flowNameAdded = "Acl_Filter_Ingress_" + aap.getIpAddress().stringValue() + "_" + aclTag;
245
246         addFlowEntryToList(flowEntries, dpId, getAclRemoteAclTable(), flowNameAdded, AclConstants.ACL_DEFAULT_PRIORITY,
247                 0, 0, AclConstants.COOKIE_ACL_BASE, flowMatches, instructions, addOrRemove);
248     }
249
250     /**
251      * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
252      *
253      * @param flowEntries the flow entries
254      * @param dpId the dpid
255      * @param lportTag the lport tag
256      * @param addOrRemove is write or delete
257      */
258     protected void ingressAclDhcpAllowServerTraffic(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
259             int addOrRemove) {
260         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_SERVER_PORT_IPV4,
261                 AclConstants.DHCP_CLIENT_PORT_IPV4, lportTag, serviceMode);
262         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
263
264         String flowName = "Ingress_DHCP_Server_v4" + dpId + "_" + lportTag + "_Permit_";
265         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
266                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
267                 instructions, addOrRemove);
268     }
269
270     /**
271      * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
272      *
273      * @param flowEntries the flow entries
274      * @param dpId the dpid
275      * @param lportTag the lport tag
276      * @param addOrRemove is write or delete
277      */
278     protected void ingressAclDhcpv6AllowServerTraffic(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
279             int addOrRemove) {
280         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_SERVER_PORT_IPV6,
281                 AclConstants.DHCP_CLIENT_PORT_IPV6, lportTag, serviceMode);
282         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
283
284         String flowName = "Ingress_DHCP_Server_v6" + "_" + dpId + "_" + lportTag + "_Permit_";
285         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
286                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
287                 instructions, addOrRemove);
288     }
289
290     /**
291      * Add rules to ensure that certain ICMPv6 like MLD_QUERY (130), RS (134), NS (135), NA (136) are
292      * allowed into the VM.
293      *
294      * @param flowEntries the flow entries
295      * @param port the port
296      * @param port type
297      * @param addOrRemove is write or delete
298      */
299     private void ingressAclIcmpv6AllowedTraffic(List<FlowEntity> flowEntries, AclInterface port,
300             InterfaceType interfaceType, int addOrRemove) {
301         BigInteger dpId = port.getDpId();
302         int lportTag = port.getLPortTag();
303         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
304
305         final short tableId = getAclAntiSpoofingTable();
306
307         if (interfaceType != InterfaceType.DhcpService) {
308             // Allow ICMPv6 Multicast Listener Query packets.
309             List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_MLD_QUERY, 0,
310                     lportTag, serviceMode);
311             String flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_"
312                     + AclConstants.ICMPV6_TYPE_MLD_QUERY + "_Permit_";
313             addFlowEntryToList(flowEntries, dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, 0, 0,
314                     AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
315         }
316
317         // Allow ICMPv6 Neighbor Solicitation packets.
318         List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NS, 0, lportTag,
319                 serviceMode);
320
321         String flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_"
322                 + AclConstants.ICMPV6_TYPE_NS + "_Permit_";
323         addFlowEntryToList(flowEntries, dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, 0, 0,
324                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
325
326         // Allow ICMPv6 Neighbor Advertisement packets.
327         matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NA, 0, lportTag, serviceMode);
328
329         flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_NA + "_Permit_";
330         addFlowEntryToList(flowEntries, dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, 0, 0,
331                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
332     }
333
334     @Override
335     protected void programIcmpv6RARule(List<FlowEntity> flowEntries, AclInterface port, List<SubnetInfo> subnets,
336             int addOrRemove) {
337         if (AclServiceUtils.isIpv6Subnet(subnets)) {
338             /* Allow ICMPv6 Router Advertisement packets from external routers as well as internal routers
339              * if subnet is configured with IPv6 version
340              * Allow ICMPv6 Router Advertisement packets if originating from any LinkLocal Address.
341              */
342             List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
343             List<MatchInfoBase> matches =
344                     AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0,
345                             port.getLPortTag(), serviceMode);
346             matches.addAll(AclServiceUtils.buildIpMatches(
347                     new IpPrefixOrAddress(IpPrefixBuilder.getDefaultInstance(AclConstants.IPV6_LINK_LOCAL_PREFIX)),
348                     AclServiceManager.MatchCriteria.MATCH_SOURCE));
349             String flowName = "Ingress_ICMPv6" + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
350                     + AclConstants.ICMPV6_TYPE_RA + "_LinkLocal_Permit_";
351             addFlowEntryToList(flowEntries, port.getDpId(), getAclAntiSpoofingTable(), flowName,
352                     AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
353                     instructions, addOrRemove);
354         }
355     }
356
357     /**
358      * Adds the rule to allow arp packets.
359      *
360      * @param flowEntries the flow entries
361      * @param dpId the dpId
362      * @param lportTag the lport tag
363      * @param addOrRemove whether to add or remove the flow
364      */
365     protected void programArpRule(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag, int addOrRemove) {
366         List<MatchInfoBase> matches = new ArrayList<>();
367         matches.add(MatchEthernetType.ARP);
368         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
369         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
370         LOG.debug("{} ARP Rule on DPID {}, lportTag {}", addOrRemove == NwConstants.DEL_FLOW ? "Deleting" : "Adding",
371                 dpId, lportTag);
372         String flowName = "Ingress_ARP_" + dpId + "_" + lportTag;
373         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
374                 AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
375                 instructions, addOrRemove);
376     }
377
378
379     /**
380      * Programs broadcast rules.
381      *
382      * @param flowEntries the flow entries
383      * @param port the Acl Interface port
384      * @param addOrRemove whether to delete or add flow
385      */
386     @Override
387     protected void programBroadcastRules(List<FlowEntity> flowEntries, AclInterface port, Action action,
388             int addOrRemove) {
389         programIpv4BroadcastRule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
390     }
391
392     /**
393      * Programs broadcast rules.
394      *
395      * @param flowEntries the flow entries
396      * @param port the Acl Interface port
397      * @param subnetInfoList the port subnet info list
398      * @param addOrRemove whether to delete or add flow
399      */
400     protected void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
401             List<SubnetInfo> subnetInfoList, int addOrRemove) {
402         programIpv4BroadcastRule(flowEntries, port, subnetInfoList, addOrRemove);
403     }
404
405     /**
406      * Programs IPv4 broadcast rules.
407      *
408      * @param flowEntries the flow entries
409      * @param port the Acl Interface port
410      * @param subnetInfoList Port subnet list
411      * @param addOrRemove whether to delete or add flow
412      */
413     private void programIpv4BroadcastRule(List<FlowEntity> flowEntries, AclInterface port,
414             List<SubnetInfo> subnetInfoList, int addOrRemove) {
415         BigInteger dpId = port.getDpId();
416         int lportTag = port.getLPortTag();
417         MatchInfoBase lportMatchInfo = AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode);
418         if (subnetInfoList != null) {
419             List<String> broadcastAddresses = AclServiceUtils.getIpBroadcastAddresses(subnetInfoList);
420             for (String broadcastAddress : broadcastAddresses) {
421                 List<MatchInfoBase> matches =
422                         AclServiceUtils.buildBroadcastIpV4Matches(broadcastAddress);
423                 matches.add(lportMatchInfo);
424                 List<InstructionInfo> instructions = new ArrayList<>();
425                 instructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
426                 String flowName = "Ingress_v4_Broadcast_" + dpId + "_" + lportTag + "_" + broadcastAddress + "_Permit";
427                 addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
428                         AclConstants.PROTO_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
429                         addOrRemove);
430             }
431         } else {
432             LOG.warn("IP Broadcast CIDRs are missing for port {}", port.getInterfaceId());
433         }
434     }
435
436     /**
437      * Add rule to ensure only DHCP client traffic is allowed.
438      *
439      * @param flowEntries the flow entries
440      * @param dpId the dpid
441      * @param lportTag the lport tag
442      * @param addOrRemove is write or delete
443      */
444     protected void allowDhcpClientTraffic(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
445             int addOrRemove) {
446         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_CLIENT_PORT_IPV4,
447                 AclConstants.DHCP_SERVER_PORT_IPV4, lportTag, serviceMode);
448         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
449
450         String flowName = "Ingress_DHCP_Service_v4" + dpId + "_" + lportTag + "_Permit_";
451         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
452                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
453                 instructions, addOrRemove);
454     }
455
456     /**
457      * Add rule to ensure only DHCPv6 client traffic is allowed.
458      *
459      * @param flowEntries the flow entries
460      * @param dpId the dpid
461      * @param lportTag the lport tag
462      * @param addOrRemove is write or delete
463      */
464     protected void allowDhcpv6ClientTraffic(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
465             int addOrRemove) {
466         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_CLIENT_PORT_IPV6,
467                 AclConstants.DHCP_SERVER_PORT_IPV6, lportTag, serviceMode);
468         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
469
470         String flowName = "Ingress_DHCP_Service_v6" + "_" + dpId + "_" + lportTag + "_Permit_";
471         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
472                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
473                 instructions, addOrRemove);
474     }
475
476     /**
477      * Add rules to allow ICMP traffic for DHCP server.
478      * @param flowEntries the flow entries
479      * @param port the Acl Interface port
480      * @param allowedAddresses the allowed addresses
481      * @param addOrRemove the lport tag
482      */
483     protected void allowIcmpTrafficToDhcpServer(List<FlowEntity> flowEntries, AclInterface port,
484             List<AllowedAddressPairs> allowedAddresses, int addOrRemove) {
485         BigInteger dpId = port.getDpId();
486         int lportTag = port.getLPortTag();
487         for (AllowedAddressPairs allowedAddress : allowedAddresses) {
488             if (AclServiceUtils.isIPv4Address(allowedAddress)) {
489                 MatchInfo reqMatchInfo = new MatchIcmpv4((short) AclConstants.ICMPV4_TYPE_ECHO_REQUEST, (short) 0);
490                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMP, reqMatchInfo,
491                         AclConstants.ICMPV4_TYPE_ECHO_REQUEST, addOrRemove);
492                 MatchInfo replyMatchInfo = new MatchIcmpv4((short) AclConstants.ICMPV4_TYPE_ECHO_REPLY, (short) 0);
493                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMP, replyMatchInfo,
494                         AclConstants.ICMPV4_TYPE_ECHO_REPLY, addOrRemove);
495             } else {
496                 MatchInfo reqMatchInfo = new MatchIcmpv6((short) AclConstants.ICMPV6_TYPE_ECHO_REQUEST, (short) 0);
497                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMPV6, reqMatchInfo,
498                         AclConstants.ICMPV6_TYPE_ECHO_REQUEST, addOrRemove);
499                 MatchInfo replyMatchInfo = new MatchIcmpv6((short) AclConstants.ICMPV6_TYPE_ECHO_REPLY, (short) 0);
500                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMPV6, replyMatchInfo,
501                         AclConstants.ICMPV6_TYPE_ECHO_REPLY, addOrRemove);
502             }
503         }
504     }
505
506     private void programIcmpFlow(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
507             AllowedAddressPairs allowedAddress, MatchIpProtocol protocol, MatchInfo icmpTypeMatchInfo,
508             int icmpType, int addOrRemove) {
509         List<MatchInfoBase> matches = new ArrayList<>();
510         matches.add(protocol);
511         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
512         matches.add(new MatchEthernetDestination(allowedAddress.getMacAddress()));
513         matches.addAll(AclServiceUtils.buildIpMatches(allowedAddress.getIpAddress(), MatchCriteria.MATCH_DESTINATION));
514         matches.add(icmpTypeMatchInfo);
515
516         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
517         String flowName = "Ingress_DHCP_Service_ICMP_" + dpId + "_" + lportTag + "_" + icmpType + "_Permit_";
518         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
519                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
520                 instructions, addOrRemove);
521     }
522
523     /**
524      * Add rule to drop BUM traffic to DHCP Server.
525      *
526      * @param flowEntries the flow entries
527      * @param dpId the dpid
528      * @param lportTag the lport tag
529      * @param addOrRemove is write or delete
530      */
531     protected void dropTrafficToDhcpServer(List<FlowEntity> flowEntries, BigInteger dpId, int lportTag,
532             int addOrRemove) {
533         InstructionInfo writeMetatdata = AclServiceUtils.getWriteMetadataForDropFlag();
534         List<InstructionInfo> instructions = Lists.newArrayList(writeMetatdata);
535         instructions.addAll(AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable()));
536
537         List<MatchInfoBase> matches = new ArrayList<>();
538         matches.add(new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
539                 MetaDataUtil.getLportTagMaskForReg6()));
540
541         String flowName = "Ingress_DHCP_Service_" + dpId + "_" + lportTag + "_Drop";
542         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
543                 AclConstants.PROTO_DHCP_SERVER_DROP_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
544                 instructions, addOrRemove);
545     }
546
547     @Override
548     protected boolean isValidDirection(Class<? extends DirectionBase> direction) {
549         return direction.equals(DirectionIngress.class);
550     }
551
552     private short getAclAntiSpoofingTable() {
553         return NwConstants.EGRESS_ACL_ANTI_SPOOFING_TABLE;
554     }
555
556     private short getAclConntrackClassifierTable() {
557         return NwConstants.EGRESS_ACL_CONNTRACK_CLASSIFIER_TABLE;
558     }
559
560     @Override
561     protected short getAclConntrackSenderTable() {
562         return NwConstants.EGRESS_ACL_CONNTRACK_SENDER_TABLE;
563     }
564
565     @Override
566     protected short getAclForExistingTrafficTable() {
567         return NwConstants.EGRESS_ACL_FOR_EXISTING_TRAFFIC_TABLE;
568     }
569
570     @Override
571     protected short getAclFilterCumDispatcherTable() {
572         return NwConstants.EGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE;
573     }
574
575     @Override
576     protected short getAclRuleBasedFilterTable() {
577         return NwConstants.EGRESS_ACL_RULE_BASED_FILTER_TABLE;
578     }
579
580     @Override
581     protected short getAclRemoteAclTable() {
582         return NwConstants.EGRESS_REMOTE_ACL_TABLE;
583     }
584
585     @Override
586     protected short getAclCommitterTable() {
587         return NwConstants.EGRESS_ACL_COMMITTER_TABLE;
588     }
589 }