9b0c3a00b1f7cf45a3ad5fdfdcbfdebef8a5b0c4
[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.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.genius.mdsalutil.FlowEntity;
20 import org.opendaylight.genius.mdsalutil.InstructionInfo;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.genius.mdsalutil.MatchInfo;
23 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
24 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
29 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
30 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv4;
31 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
32 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
33 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
34 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
35 import org.opendaylight.genius.utils.ServiceIndex;
36 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
37 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
38 import org.opendaylight.netvirt.aclservice.api.AclServiceManager;
39 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
40 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
41 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
42 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
43 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
44 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
45 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefixBuilder;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl.InterfaceType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.SubnetInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.opendaylight.yangtools.yang.common.Uint64;
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, serviceMode);
112
113             return Collections.singletonList(
114                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.put(
115                             path, serviceInfo, CREATE_MISSING_PARENTS)));
116         });
117     }
118
119     /**
120      * Unbind service.
121      *
122      * @param aclInterface the acl interface
123      */
124     @Override
125     protected void unbindService(AclInterface aclInterface) {
126         String interfaceName = aclInterface.getInterfaceId();
127         InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
128                 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
129                 serviceMode);
130
131         LOG.debug("UnBinding ACL service for interface {}", interfaceName);
132         jobCoordinator.enqueueJob(interfaceName, () -> Collections.singletonList(txRunner
133                 .callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(path))));
134     }
135
136     /**
137      * Programs DHCP Service flows.
138      *
139      * @param flowEntries the flow entries
140      * @param port the acl interface
141      * @param action add/modify/remove action
142      * @param addOrRemove addorRemove
143      */
144     @Override
145     protected void programDhcpService(List<FlowEntity> flowEntries, AclInterface port,
146             Action action, int addOrRemove) {
147         LOG.info("{} programDhcpService for port {}, action={}, addOrRemove={}", this.directionString,
148                 port.getInterfaceId(), action, addOrRemove);
149         Uint64 dpid = Uint64.valueOf(port.getDpId());
150         int lportTag = port.getLPortTag();
151         allowDhcpClientTraffic(flowEntries, dpid, lportTag, addOrRemove);
152         allowDhcpv6ClientTraffic(flowEntries, dpid, lportTag, addOrRemove);
153         programArpRule(flowEntries, dpid, lportTag, addOrRemove);
154         ingressAclIcmpv6AllowedTraffic(flowEntries, port, InterfaceType.DhcpService, addOrRemove);
155         allowIcmpTrafficToDhcpServer(flowEntries, port, port.getAllowedAddressPairs(), addOrRemove);
156         dropTrafficToDhcpServer(flowEntries, dpid, lportTag, addOrRemove);
157         programCommitterDropFlow(flowEntries, dpid, lportTag, addOrRemove);
158     }
159
160     /**
161      * Programs DHCP service flows.
162      *
163      * @param flowEntries the flow entries
164      * @param port the acl interface
165      * @param allowedAddresses the allowed addresses
166      * @param addOrRemove addorRemove
167      */
168     @Override
169     protected void processDhcpServiceUpdate(List<FlowEntity> flowEntries, AclInterface port,
170             List<AllowedAddressPairs> allowedAddresses, int addOrRemove) {
171         allowIcmpTrafficToDhcpServer(flowEntries, port, allowedAddresses, addOrRemove);
172     }
173
174     @Override
175     protected void programAntiSpoofingRules(List<FlowEntity> flowEntries, AclInterface port,
176             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
177         LOG.info("{} programAntiSpoofingRules for port {}, AAPs={}, action={}, addOrRemove={}", this.directionString,
178                 port.getInterfaceId(), allowedAddresses, action, addOrRemove);
179
180         Uint64 dpid = Uint64.valueOf(port.getDpId());
181         int lportTag = port.getLPortTag();
182         if (action == Action.ADD || action == Action.REMOVE) {
183             programCommitterDropFlow(flowEntries, dpid, lportTag, addOrRemove);
184             ingressAclDhcpAllowServerTraffic(flowEntries, dpid, lportTag, addOrRemove);
185             ingressAclDhcpv6AllowServerTraffic(flowEntries, dpid, lportTag, addOrRemove);
186             ingressAclIcmpv6AllowedTraffic(flowEntries, port, InterfaceType.AccessPort, addOrRemove);
187             programIcmpv6RARule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
188
189             programArpRule(flowEntries, dpid, lportTag, addOrRemove);
190             programIpv4BroadcastRule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
191         }
192     }
193
194     private void programCommitterDropFlow(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
195             int addOrRemove) {
196         List<MatchInfoBase> matches = new ArrayList<>();
197         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
198
199         Uint64 metaData = Uint64.fromLongBits(MetaDataUtil.METADATA_MASK_ACL_DROP.longValue()
200                 & (AclConstants.METADATA_DROP_FLAG.longValue() << 2));
201         Uint64 metaDataMask = Uint64.fromLongBits(MetaDataUtil.METADATA_MASK_ACL_DROP.longValue()
202                 & (AclConstants.METADATA_DROP_FLAG.longValue() << 2));
203
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, Uint64 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 + "_"
230                     + mac.getValue() + "_" + 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, Uint64 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, Uint64 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, Uint64 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         Uint64 dpId = Uint64.valueOf(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             return;
339         }
340
341         Uint64 dpid = Uint64.valueOf(port.getDpId());
342         /* Allow ICMPv6 Router Advertisement packets from external routers as well as internal routers
343          * if subnet is configured with IPv6 version
344          * Allow ICMPv6 Router Advertisement packets if originating from any LinkLocal Address.
345          */
346         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
347         List<MatchInfoBase> matches =
348                 AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0,
349                         port.getLPortTag(), serviceMode);
350         matches.addAll(AclServiceUtils.buildIpMatches(
351                 new IpPrefixOrAddress(IpPrefixBuilder.getDefaultInstance(AclConstants.IPV6_LINK_LOCAL_PREFIX)),
352                 AclServiceManager.MatchCriteria.MATCH_SOURCE));
353         String flowName = "Ingress_ICMPv6" + "_" + dpid + "_" + port.getLPortTag() + "_"
354                 + AclConstants.ICMPV6_TYPE_RA + "_LinkLocal_Permit_";
355         addFlowEntryToList(flowEntries, dpid, getAclAntiSpoofingTable(), flowName,
356                 AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
357                 instructions, addOrRemove);
358     }
359
360     /**
361      * Adds the rule to allow arp packets.
362      *
363      * @param flowEntries the flow entries
364      * @param dpId the dpId
365      * @param lportTag the lport tag
366      * @param addOrRemove whether to add or remove the flow
367      */
368     protected void programArpRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag, int addOrRemove) {
369         List<MatchInfoBase> matches = new ArrayList<>();
370         matches.add(MatchEthernetType.ARP);
371         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
372         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
373         LOG.debug("{} ARP Rule on DPID {}, lportTag {}", addOrRemove == NwConstants.DEL_FLOW ? "Deleting" : "Adding",
374                 dpId, lportTag);
375         String flowName = "Ingress_ARP_" + dpId + "_" + lportTag;
376         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
377                 AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
378                 instructions, addOrRemove);
379     }
380
381
382     /**
383      * Programs broadcast rules.
384      *
385      * @param flowEntries the flow entries
386      * @param port the Acl Interface port
387      * @param addOrRemove whether to delete or add flow
388      */
389     @Override
390     protected void programBroadcastRules(List<FlowEntity> flowEntries, AclInterface port, Action action,
391             int addOrRemove) {
392         programIpv4BroadcastRule(flowEntries, port, port.getSubnetInfo(), addOrRemove);
393     }
394
395     /**
396      * Programs broadcast rules.
397      *
398      * @param flowEntries the flow entries
399      * @param port the Acl Interface port
400      * @param subnetInfoList the port subnet info list
401      * @param addOrRemove whether to delete or add flow
402      */
403     protected void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
404             List<SubnetInfo> subnetInfoList, int addOrRemove) {
405         programIpv4BroadcastRule(flowEntries, port, subnetInfoList, addOrRemove);
406     }
407
408     /**
409      * Programs IPv4 broadcast rules.
410      *
411      * @param flowEntries the flow entries
412      * @param port the Acl Interface port
413      * @param subnetInfoList Port subnet list
414      * @param addOrRemove whether to delete or add flow
415      */
416     private void programIpv4BroadcastRule(List<FlowEntity> flowEntries, AclInterface port,
417             List<SubnetInfo> subnetInfoList, int addOrRemove) {
418         Uint64 dpId = Uint64.valueOf(port.getDpId());
419         int lportTag = port.getLPortTag();
420         MatchInfoBase lportMatchInfo = AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode);
421         if (subnetInfoList != null) {
422             List<String> broadcastAddresses = AclServiceUtils.getIpBroadcastAddresses(subnetInfoList);
423             for (String broadcastAddress : broadcastAddresses) {
424                 List<MatchInfoBase> matches =
425                         AclServiceUtils.buildBroadcastIpV4Matches(broadcastAddress);
426                 matches.add(lportMatchInfo);
427                 List<InstructionInfo> instructions = new ArrayList<>();
428                 instructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
429                 String flowName = "Ingress_v4_Broadcast_" + dpId + "_"
430                                     + lportTag + "_" + broadcastAddress + "_Permit";
431                 addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
432                         AclConstants.PROTO_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
433                         addOrRemove);
434             }
435         } else {
436             LOG.warn("IP Broadcast CIDRs are missing for port {}", port.getInterfaceId());
437         }
438     }
439
440     /**
441      * Add rule to ensure only DHCP client traffic is allowed.
442      *
443      * @param flowEntries the flow entries
444      * @param dpId the dpid
445      * @param lportTag the lport tag
446      * @param addOrRemove is write or delete
447      */
448     protected void allowDhcpClientTraffic(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
449             int addOrRemove) {
450         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_CLIENT_PORT_IPV4,
451                 AclConstants.DHCP_SERVER_PORT_IPV4, lportTag, serviceMode);
452         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
453
454         String flowName = "Ingress_DHCP_Service_v4" + dpId + "_" + lportTag + "_Permit_";
455         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
456                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
457                 instructions, addOrRemove);
458     }
459
460     /**
461      * Add rule to ensure only DHCPv6 client traffic is allowed.
462      *
463      * @param flowEntries the flow entries
464      * @param dpId the dpid
465      * @param lportTag the lport tag
466      * @param addOrRemove is write or delete
467      */
468     protected void allowDhcpv6ClientTraffic(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
469             int addOrRemove) {
470         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_CLIENT_PORT_IPV6,
471                 AclConstants.DHCP_SERVER_PORT_IPV6, lportTag, serviceMode);
472         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
473
474         String flowName = "Ingress_DHCP_Service_v6" + "_" + dpId + "_" + lportTag + "_Permit_";
475         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
476                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
477                 instructions, addOrRemove);
478     }
479
480     /**
481      * Add rules to allow ICMP traffic for DHCP server.
482      * @param flowEntries the flow entries
483      * @param port the Acl Interface port
484      * @param allowedAddresses the allowed addresses
485      * @param addOrRemove the lport tag
486      */
487     protected void allowIcmpTrafficToDhcpServer(List<FlowEntity> flowEntries, AclInterface port,
488             List<AllowedAddressPairs> allowedAddresses, int addOrRemove) {
489         Uint64 dpId = Uint64.valueOf(port.getDpId());
490         int lportTag = port.getLPortTag();
491         for (AllowedAddressPairs allowedAddress : allowedAddresses) {
492             if (AclServiceUtils.isIPv4Address(allowedAddress)) {
493                 MatchInfo reqMatchInfo = new MatchIcmpv4((short) AclConstants.ICMPV4_TYPE_ECHO_REQUEST, (short) 0);
494                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMP, reqMatchInfo,
495                         AclConstants.ICMPV4_TYPE_ECHO_REQUEST, addOrRemove);
496                 MatchInfo replyMatchInfo = new MatchIcmpv4((short) AclConstants.ICMPV4_TYPE_ECHO_REPLY, (short) 0);
497                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMP, replyMatchInfo,
498                         AclConstants.ICMPV4_TYPE_ECHO_REPLY, addOrRemove);
499             } else {
500                 MatchInfo reqMatchInfo = new MatchIcmpv6((short) AclConstants.ICMPV6_TYPE_ECHO_REQUEST, (short) 0);
501                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMPV6, reqMatchInfo,
502                         AclConstants.ICMPV6_TYPE_ECHO_REQUEST, addOrRemove);
503                 MatchInfo replyMatchInfo = new MatchIcmpv6((short) AclConstants.ICMPV6_TYPE_ECHO_REPLY, (short) 0);
504                 programIcmpFlow(flowEntries, dpId, lportTag, allowedAddress, MatchIpProtocol.ICMPV6, replyMatchInfo,
505                         AclConstants.ICMPV6_TYPE_ECHO_REPLY, addOrRemove);
506             }
507         }
508     }
509
510     private void programIcmpFlow(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
511             AllowedAddressPairs allowedAddress, MatchIpProtocol protocol, MatchInfo icmpTypeMatchInfo,
512             int icmpType, int addOrRemove) {
513         List<MatchInfoBase> matches = new ArrayList<>();
514         matches.add(protocol);
515         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
516         matches.add(new MatchEthernetDestination(allowedAddress.getMacAddress()));
517         matches.addAll(AclServiceUtils.buildIpMatches(allowedAddress.getIpAddress(), MatchCriteria.MATCH_DESTINATION));
518         matches.add(icmpTypeMatchInfo);
519
520         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
521         String flowName = "Ingress_DHCP_Service_ICMP_" + dpId + "_" + lportTag + "_" + icmpType + "_Permit_";
522         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
523                 AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
524                 instructions, addOrRemove);
525     }
526
527     /**
528      * Add rule to drop BUM traffic to DHCP Server.
529      *
530      * @param flowEntries the flow entries
531      * @param dpId the dpid
532      * @param lportTag the lport tag
533      * @param addOrRemove is write or delete
534      */
535     protected void dropTrafficToDhcpServer(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
536             int addOrRemove) {
537         InstructionInfo writeMetatdata = AclServiceUtils.getWriteMetadataForDropFlag();
538         List<InstructionInfo> instructions = Lists.newArrayList(writeMetatdata);
539         instructions.addAll(AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable()));
540
541         List<MatchInfoBase> matches = new ArrayList<>();
542         matches.add(new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
543                 MetaDataUtil.getLportTagMaskForReg6()));
544
545         String flowName = "Ingress_DHCP_Service_" + dpId + "_" + lportTag + "_Drop";
546         addFlowEntryToList(flowEntries, dpId, getAclAntiSpoofingTable(), flowName,
547                 AclConstants.PROTO_DHCP_SERVER_DROP_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
548                 instructions, addOrRemove);
549     }
550
551     @Override
552     protected boolean isValidDirection(Class<? extends DirectionBase> direction) {
553         return direction.equals(DirectionIngress.class);
554     }
555
556     private short getAclAntiSpoofingTable() {
557         return NwConstants.EGRESS_ACL_ANTI_SPOOFING_TABLE;
558     }
559
560     private short getAclConntrackClassifierTable() {
561         return NwConstants.EGRESS_ACL_CONNTRACK_CLASSIFIER_TABLE;
562     }
563
564     @Override
565     protected short getAclConntrackSenderTable() {
566         return NwConstants.EGRESS_ACL_CONNTRACK_SENDER_TABLE;
567     }
568
569     @Override
570     protected short getAclForExistingTrafficTable() {
571         return NwConstants.EGRESS_ACL_FOR_EXISTING_TRAFFIC_TABLE;
572     }
573
574     @Override
575     protected short getAclFilterCumDispatcherTable() {
576         return NwConstants.EGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE;
577     }
578
579     @Override
580     protected short getAclRuleBasedFilterTable() {
581         return NwConstants.EGRESS_ACL_RULE_BASED_FILTER_TABLE;
582     }
583
584     @Override
585     protected short getAclRemoteAclTable() {
586         return NwConstants.EGRESS_REMOTE_ACL_TABLE;
587     }
588
589     @Override
590     protected short getAclCommitterTable() {
591         return NwConstants.EGRESS_ACL_COMMITTER_TABLE;
592     }
593 }