Remove unused parameters
[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 java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.mdsalutil.InstructionInfo;
18 import org.opendaylight.genius.mdsalutil.MDSALUtil;
19 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
24 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
25 import org.opendaylight.genius.utils.ServiceIndex;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
28 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
29 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
30 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
31 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
32 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
33 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
34 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * Provides the implementation for ingress (w.r.t VM) ACL service.
49  *
50  * <p>
51  * Note: Table names used are w.r.t switch. Hence, switch ingress is VM egress
52  * and vice versa.
53  */
54 public class IngressAclServiceImpl extends AbstractAclServiceImpl {
55
56     private static final Logger LOG = LoggerFactory.getLogger(IngressAclServiceImpl.class);
57
58     /**
59      * Initialize the member variables.
60      *
61      * @param dataBroker the data broker instance.
62      * @param mdsalManager the mdsal manager.
63      * @param aclDataUtil the acl data util.
64      * @param aclServiceUtils the acl service util.
65      * @param jobCoordinator the job coordinator
66      * @param aclInterfaceCache the acl interface cache
67      */
68     public IngressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
69             AclServiceUtils aclServiceUtils, JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
70         // Service mode is w.rt. switch
71         super(ServiceModeEgress.class, dataBroker, mdsalManager, aclDataUtil, aclServiceUtils, jobCoordinator,
72                 aclInterfaceCache);
73     }
74
75     /**
76      * Bind service.
77      *
78      * @param aclInterface the acl interface
79      */
80     @Override
81     public void bindService(AclInterface aclInterface) {
82         String interfaceName = aclInterface.getInterfaceId();
83         jobCoordinator.enqueueJob(interfaceName, () -> {
84             int instructionKey = 0;
85             List<Instruction> instructions = new ArrayList<>();
86             instructions.add(
87                     MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.EGRESS_ACL_DUMMY_TABLE, ++instructionKey));
88             int flowPriority = NwConstants.EGRESS_ACL_SERVICE_INDEX;
89             short serviceIndex =
90                     ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX);
91             BoundServices serviceInfo =
92                     AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "acl", "egressacl", interfaceName),
93                             serviceIndex, flowPriority, AclConstants.COOKIE_ACL_BASE, instructions);
94             InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
95                     ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
96                     serviceMode);
97
98             return Collections.singletonList(
99                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.put(LogicalDatastoreType.CONFIGURATION,
100                             path, serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS)));
101         });
102     }
103
104     /**
105      * Unbind service.
106      *
107      * @param aclInterface the acl interface
108      */
109     @Override
110     protected void unbindService(AclInterface aclInterface) {
111         String interfaceName = aclInterface.getInterfaceId();
112         InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
113                 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
114                 serviceMode);
115
116         LOG.debug("UnBinding ACL service for interface {}", interfaceName);
117         jobCoordinator.enqueueJob(interfaceName, () -> Collections.singletonList(txRunner
118                 .callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(LogicalDatastoreType.CONFIGURATION, path))));
119     }
120
121     @Override
122     protected void programAntiSpoofingRules(AclInterface port,
123             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
124         LOG.info("{} programAntiSpoofingRules for port {}, AAPs={}, action={}, addOrRemove={}", this.directionString,
125                 port.getInterfaceId(), allowedAddresses, action, addOrRemove);
126
127         BigInteger dpid = port.getDpId();
128         int lportTag = port.getLPortTag();
129         if (action == Action.ADD || action == Action.REMOVE) {
130             ingressAclDhcpAllowServerTraffic(dpid, lportTag, addOrRemove);
131             ingressAclDhcpv6AllowServerTraffic(dpid, lportTag, addOrRemove);
132             ingressAclIcmpv6AllowedTraffic(dpid, lportTag, addOrRemove);
133
134             programArpRule(dpid, lportTag, addOrRemove);
135             programIpv4BroadcastRule(port, addOrRemove);
136         }
137     }
138
139     @Override
140     protected void programGotoClassifierTableRules(BigInteger dpId, List<AllowedAddressPairs> aaps, int lportTag,
141             int addOrRemove) {
142         for (AllowedAddressPairs aap : aaps) {
143             IpPrefixOrAddress attachIp = aap.getIpAddress();
144             MacAddress mac = aap.getMacAddress();
145
146             List<MatchInfoBase> matches = new ArrayList<>();
147             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
148             matches.add(new MatchEthernetDestination(mac));
149             matches.addAll(AclServiceUtils.buildIpMatches(attachIp, MatchCriteria.MATCH_DESTINATION));
150
151             List<InstructionInfo> gotoInstructions = new ArrayList<>();
152             gotoInstructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
153
154             String flowName = "Ingress_Fixed_Goto_Classifier_" + dpId + "_" + lportTag + "_" + mac.getValue() + "_"
155                     + String.valueOf(attachIp.getValue());
156             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
157                     AclConstants.COOKIE_ACL_BASE, matches, gotoInstructions, addOrRemove);
158         }
159     }
160
161     @Override
162     protected void programRemoteAclTableFlow(BigInteger dpId, Integer aclTag, AllowedAddressPairs aap,
163             int addOrRemove) {
164         List<MatchInfoBase> flowMatches = new ArrayList<>();
165         flowMatches.addAll(AclServiceUtils.buildIpAndSrcServiceMatch(aclTag, aap));
166
167         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
168         String flowNameAdded = "Acl_Filter_Ingress_" + String.valueOf(aap.getIpAddress().getValue()) + "_" + aclTag;
169
170         syncFlow(dpId, getAclRemoteAclTable(), flowNameAdded, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
171                 AclConstants.COOKIE_ACL_BASE, flowMatches, instructions, addOrRemove);
172     }
173
174     /**
175      * Add rule to ensure only DHCP server traffic from the specified mac is
176      * allowed.
177      *
178      * @param dpId the dpid
179      * @param lportTag the lport tag
180      * @param addOrRemove is write or delete
181      */
182     protected void ingressAclDhcpAllowServerTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
183         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_SERVER_PORT_IPV4,
184                 AclConstants.DHCP_CLIENT_PORT_IPV4, lportTag, serviceMode);
185         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
186
187         String flowName = "Ingress_DHCP_Server_v4" + dpId + "_" + lportTag + "_Permit_";
188         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, "ACL", 0, 0,
189                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
190     }
191
192     /**
193      * Add rule to ensure only DHCPv6 server traffic from the specified mac is
194      * allowed.
195      *
196      * @param dpId the dpid
197      * @param lportTag the lport tag
198      * @param addOrRemove is write or delete
199      */
200     protected void ingressAclDhcpv6AllowServerTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
201         final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_SERVER_PORT_IPV6,
202                 AclConstants.DHCP_CLIENT_PORT_IPV6, lportTag, serviceMode);
203         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
204
205         String flowName = "Ingress_DHCP_Server_v6" + "_" + dpId + "_" + lportTag + "_Permit_";
206         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, "ACL", 0, 0,
207                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
208     }
209
210     /**
211      * Add rules to ensure that certain ICMPv6 like MLD_QUERY (130), NS (135), NA (136) are allowed into the VM.
212      *
213      * @param dpId the dpid
214      * @param lportTag the lport tag
215      * @param addOrRemove is write or delete
216      */
217     private void ingressAclIcmpv6AllowedTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
218         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
219
220         // Allow ICMPv6 Multicast Listener Query packets.
221         List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_MLD_QUERY, 0,
222                 lportTag, serviceMode);
223
224         final short tableId = getAclAntiSpoofingTable();
225         String flowName =
226                 "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_MLD_QUERY + "_Permit_";
227         syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
228                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
229
230         // Allow ICMPv6 Neighbor Solicitation packets.
231         matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NS, 0, lportTag, serviceMode);
232
233         flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_NS + "_Permit_";
234         syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
235                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
236
237         // Allow ICMPv6 Neighbor Advertisement packets.
238         matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NA, 0, lportTag, serviceMode);
239
240         flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_NA + "_Permit_";
241         syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
242                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
243     }
244
245     /**
246      * Adds the rule to allow arp packets.
247      *
248      * @param dpId the dpId
249      * @param lportTag the lport tag
250      * @param addOrRemove whether to add or remove the flow
251      */
252     protected void programArpRule(BigInteger dpId, int lportTag, int addOrRemove) {
253         List<MatchInfoBase> matches = new ArrayList<>();
254         matches.add(MatchEthernetType.ARP);
255         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
256         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
257         LOG.debug(addOrRemove == NwConstants.DEL_FLOW ? "Deleting " : "Adding " + "ARP Rule on DPID {}, "
258                 + "lportTag {}", dpId, lportTag);
259         String flowName = "Ingress_ARP_" + dpId + "_" + lportTag;
260         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, "ACL", 0, 0,
261                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
262     }
263
264
265     /**
266      * Programs broadcast rules.
267      *
268      * @param port the Acl Interface port
269      * @param addOrRemove whether to delete or add flow
270      */
271     @Override
272     protected void programBroadcastRules(AclInterface port, int addOrRemove) {
273         programIpv4BroadcastRule(port, addOrRemove);
274     }
275
276     /**
277      * Programs IPv4 broadcast rules.
278      *
279      * @param port the Acl Interface port
280      * @param addOrRemove whether to delete or add flow
281      */
282     private void programIpv4BroadcastRule(AclInterface port, int addOrRemove) {
283         BigInteger dpId = port.getDpId();
284         int lportTag = port.getLPortTag();
285         MatchInfoBase lportMatchInfo = AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode);
286         List<IpPrefixOrAddress> cidrs = port.getSubnetIpPrefixes();
287         if (cidrs != null) {
288             List<String> broadcastAddresses = AclServiceUtils.getIpBroadcastAddresses(cidrs);
289             for (String broadcastAddress : broadcastAddresses) {
290                 List<MatchInfoBase> matches =
291                         AclServiceUtils.buildBroadcastIpV4Matches(broadcastAddress);
292                 matches.add(lportMatchInfo);
293                 List<InstructionInfo> instructions = new ArrayList<>();
294                 instructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
295                 String flowName = "Ingress_v4_Broadcast_" + dpId + "_" + lportTag + "_" + broadcastAddress + "_Permit";
296                 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
297                         AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
298             }
299         } else {
300             LOG.warn("IP Broadcast CIDRs are missing for port {}", port.getInterfaceId());
301         }
302     }
303
304     @Override
305     protected boolean isValidDirection(Class<? extends DirectionBase> direction) {
306         return direction.equals(DirectionIngress.class);
307     }
308
309     @Override
310     protected short getAclAntiSpoofingTable() {
311         return NwConstants.EGRESS_ACL_ANTI_SPOOFING_TABLE;
312     }
313
314     @Override
315     protected short getAclConntrackClassifierTable() {
316         return NwConstants.EGRESS_ACL_CONNTRACK_CLASSIFIER_TABLE;
317     }
318
319     @Override
320     protected short getAclConntrackSenderTable() {
321         return NwConstants.EGRESS_ACL_CONNTRACK_SENDER_TABLE;
322     }
323
324     @Override
325     protected short getAclForExistingTrafficTable() {
326         return NwConstants.EGRESS_ACL_FOR_EXISTING_TRAFFIC_TABLE;
327     }
328
329     @Override
330     protected short getAclFilterCumDispatcherTable() {
331         return NwConstants.EGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE;
332     }
333
334     @Override
335     protected short getAclRuleBasedFilterTable() {
336         return NwConstants.EGRESS_ACL_RULE_BASED_FILTER_TABLE;
337     }
338
339     @Override
340     protected short getAclRemoteAclTable() {
341         return NwConstants.EGRESS_REMOTE_ACL_TABLE;
342     }
343
344     @Override
345     protected short getAclCommitterTable() {
346         return NwConstants.EGRESS_ACL_COMMITTER_TABLE;
347     }
348 }