move vpnservice and cleanup poms
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / EgressAclServiceImpl.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 java.util.Set;
15 import java.util.stream.Collectors;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.mdsalutil.InstructionInfo;
20 import org.opendaylight.genius.mdsalutil.MDSALUtil;
21 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
22 import org.opendaylight.genius.mdsalutil.NwConstants;
23 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
24 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
25 import org.opendaylight.genius.mdsalutil.matches.MatchArpSha;
26 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
27 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
28 import org.opendaylight.genius.utils.ServiceIndex;
29 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
30 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
31 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
32 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
33 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
34 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
35 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
36 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
37 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 /**
51  * Provides the implementation for egress (w.r.t VM) ACL service.
52  *
53  * <p>
54  * Note: Table names used are w.r.t switch. Hence, switch ingress is VM egress
55  * and vice versa.
56  */
57 public class EgressAclServiceImpl extends AbstractAclServiceImpl {
58
59     private static final Logger LOG = LoggerFactory.getLogger(EgressAclServiceImpl.class);
60
61     /**
62      * Initialize the member variables.
63      */
64     public EgressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
65             AclServiceUtils aclServiceUtils, JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
66         // Service mode is w.rt. switch
67         super(ServiceModeIngress.class, dataBroker, mdsalManager, aclDataUtil, aclServiceUtils,
68                 jobCoordinator, aclInterfaceCache);
69     }
70
71     /**
72      * Bind service.
73      *
74      * @param aclInterface the acl interface
75      */
76     @Override
77     public void bindService(AclInterface aclInterface) {
78         String interfaceName = aclInterface.getInterfaceId();
79         jobCoordinator.enqueueJob(interfaceName, () -> {
80             int instructionKey = 0;
81             List<Instruction> instructions = new ArrayList<>();
82             instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(getAclAntiSpoofingTable(), ++instructionKey));
83             short serviceIndex = ServiceIndex.getIndex(AclConstants.INGRESS_ACL_SERVICE_NAME,
84                     AclConstants.INGRESS_ACL_SERVICE_INDEX);
85             int flowPriority = AclConstants.INGRESS_ACL_SERVICE_INDEX;
86             BoundServices serviceInfo =
87                     AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "acl", "ingressacl", interfaceName),
88                             serviceIndex, flowPriority, AclConstants.COOKIE_ACL_BASE, instructions);
89             InstanceIdentifier<BoundServices> path =
90                     AclServiceUtils.buildServiceId(interfaceName, serviceIndex, serviceMode);
91
92             return Collections.singletonList(
93                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.put(LogicalDatastoreType.CONFIGURATION,
94                             path, serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS)));
95         });
96     }
97
98     /**
99      * Unbind service.
100      *
101      * @param aclInterface the acl interface
102      */
103     @Override
104     protected void unbindService(AclInterface aclInterface) {
105         String interfaceName = aclInterface.getInterfaceId();
106         InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
107                 ServiceIndex.getIndex(NwConstants.ACL_SERVICE_NAME, NwConstants.ACL_SERVICE_INDEX), serviceMode);
108
109         LOG.debug("UnBinding ACL service for interface {}", interfaceName);
110         jobCoordinator.enqueueJob(interfaceName, () -> Collections.singletonList(txRunner
111                 .callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(LogicalDatastoreType.CONFIGURATION, path))));
112     }
113
114     @Override
115     protected void programAntiSpoofingRules(AclInterface port, String dhcpMacAddress,
116             List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
117         LOG.info("{} programAntiSpoofingRules for port {}, AAPs={}, action={}, addOrRemove={}", this.directionString,
118                 port.getInterfaceId(), allowedAddresses, action, addOrRemove);
119
120         BigInteger dpid = port.getDpId();
121         int lportTag = port.getLPortTag();
122         if (action == Action.ADD || action == Action.REMOVE) {
123             Set<MacAddress> aapMacs =
124                 allowedAddresses.stream().map(aap -> aap.getMacAddress()).collect(Collectors.toSet());
125             egressAclDhcpAllowClientTraffic(dpid, aapMacs, lportTag, addOrRemove);
126             egressAclDhcpv6AllowClientTraffic(dpid, aapMacs, lportTag, addOrRemove);
127             egressAclDhcpDropServerTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove);
128             egressAclDhcpv6DropServerTraffic(dpid, dhcpMacAddress, lportTag, addOrRemove);
129             egressAclIcmpv6DropRouterAdvts(dpid, lportTag, addOrRemove);
130             egressAclIcmpv6AllowedList(dpid, lportTag, addOrRemove);
131
132             programArpRule(dpid, allowedAddresses, lportTag, addOrRemove);
133             programL2BroadcastAllowRule(port, addOrRemove);
134         }
135     }
136
137     @Override
138     protected void updateArpForAllowedAddressPairs(BigInteger dpId, int lportTag, List<AllowedAddressPairs> deletedAAP,
139             List<AllowedAddressPairs> addedAAP) {
140         // Remove common allowedAddrPairIPs to avoid delete and add of ARP flows having same MAC and IP
141         deletedAAP.removeAll(addedAAP);
142         programArpRule(dpId, deletedAAP, lportTag, NwConstants.DEL_FLOW);
143         programArpRule(dpId, addedAAP, lportTag, NwConstants.ADD_FLOW);
144     }
145
146     @Override
147     protected void programRemoteAclTableFlow(BigInteger dpId, Integer aclTag, AllowedAddressPairs aap,
148             int addOrRemove) {
149         List<MatchInfoBase> flowMatches = new ArrayList<>();
150         flowMatches.addAll(AclServiceUtils.buildIpAndDstServiceMatch(aclTag, aap, dataBroker));
151
152         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
153         String flowNameAdded = "Acl_Filter_Egress_" + String.valueOf(aap.getIpAddress().getValue()) + "_" + aclTag;
154
155         syncFlow(dpId, getAclRemoteAclTable(), flowNameAdded, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
156                 AclConstants.COOKIE_ACL_BASE, flowMatches, instructions, addOrRemove);
157     }
158
159     @Override
160     protected void programGotoClassifierTableRules(BigInteger dpId, List<AllowedAddressPairs> aaps, int lportTag,
161             int addOrRemove) {
162         for (AllowedAddressPairs aap : aaps) {
163             IpPrefixOrAddress attachIp = aap.getIpAddress();
164             MacAddress mac = aap.getMacAddress();
165
166             List<MatchInfoBase> matches = new ArrayList<>();
167             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
168             matches.add(new MatchEthernetSource(mac));
169             matches.addAll(AclServiceUtils.buildIpMatches(attachIp, MatchCriteria.MATCH_SOURCE));
170
171             List<InstructionInfo> gotoInstructions = new ArrayList<>();
172             gotoInstructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
173
174             String flowName = "Egress_Fixed_Goto_Classifier_" + dpId + "_" + lportTag + "_" + mac.getValue() + "_"
175                     + String.valueOf(attachIp.getValue());
176             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
177                     AclConstants.COOKIE_ACL_BASE, matches, gotoInstructions, addOrRemove);
178         }
179     }
180
181     /**
182      * Anti-spoofing rule to block the Ipv4 DHCP server traffic from the port.
183      *
184      * @param dpId the dpId
185      * @param dhcpMacAddress the Dhcp mac address
186      * @param lportTag the lport tag
187      * @param addOrRemove add/remove the flow.
188      */
189     protected void egressAclDhcpDropServerTraffic(BigInteger dpId, String dhcpMacAddress, int lportTag,
190             int addOrRemove) {
191         List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_SERVER_PORT_IPV4,
192                 AclConstants.DHCP_CLIENT_PORT_IPV4, lportTag, serviceMode);
193
194         String flowName = "Egress_DHCP_Server_v4" + dpId + "_" + lportTag + "_" + dhcpMacAddress + "_Drop_";
195         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY,
196                 "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, Collections.emptyList(), addOrRemove);
197     }
198
199     /**
200      * Anti-spoofing rule to block the Ipv6 DHCP server traffic from the port.
201      *
202      * @param dpId the dpId
203      * @param dhcpMacAddress the Dhcp mac address
204      * @param lportTag the lport tag
205      * @param addOrRemove add/remove the flow.
206      */
207     protected void egressAclDhcpv6DropServerTraffic(BigInteger dpId, String dhcpMacAddress, int lportTag,
208             int addOrRemove) {
209         List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_SERVER_PORT_IPV6,
210                 AclConstants.DHCP_CLIENT_PORT_IPV6, lportTag, serviceMode);
211
212         String flowName = "Egress_DHCP_Server_v6" + "_" + dpId + "_" + lportTag + "_" + dhcpMacAddress + "_Drop_";
213         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY,
214                 "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, Collections.emptyList(), addOrRemove);
215     }
216
217     /**
218      * Anti-spoofing rule to block the Ipv6 Router Advts from the VM port.
219      *
220      * @param dpId the dpId
221      * @param lportTag the lport tag
222      * @param addOrRemove add/remove the flow.
223      */
224     private void egressAclIcmpv6DropRouterAdvts(BigInteger dpId, int lportTag, int addOrRemove) {
225         List<MatchInfoBase> matches =
226                 AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_RA, 0, lportTag, serviceMode);
227
228         String flowName = "Egress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_RA + "_Drop_";
229         syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_IPV6_DROP_PRIORITY, "ACL", 0, 0,
230                 AclConstants.COOKIE_ACL_BASE, matches, Collections.emptyList(), addOrRemove);
231     }
232
233     /**
234      * Add rule to allow certain ICMPv6 traffic from VM ports.
235      *
236      * @param dpId the dpId
237      * @param lportTag the lport tag
238      * @param addOrRemove add/remove the flow.
239      */
240     private void egressAclIcmpv6AllowedList(BigInteger dpId, int lportTag, int addOrRemove) {
241         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
242
243         for (Integer icmpv6Type: AclConstants.allowedIcmpv6NdList()) {
244             List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(icmpv6Type, 0, lportTag, serviceMode);
245             String flowName = "Egress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + icmpv6Type + "_Permit_";
246             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
247                     AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
248         }
249     }
250
251     /**
252      * Add rule to ensure only DHCP server traffic from the specified mac is
253      * allowed.
254      *
255      * @param dpId the dpid
256      * @param aapMacs the AAP mac addresses
257      * @param lportTag the lport tag
258      * @param addOrRemove whether to add or remove the flow
259      */
260     private void egressAclDhcpAllowClientTraffic(BigInteger dpId, Set<MacAddress> aapMacs, int lportTag,
261             int addOrRemove) {
262         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
263         for (MacAddress aapMac : aapMacs) {
264             List<MatchInfoBase> matches = new ArrayList<>();
265             matches.addAll(AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_CLIENT_PORT_IPV4,
266                 AclConstants.DHCP_SERVER_PORT_IPV4, lportTag, serviceMode));
267             matches.add(new MatchEthernetSource(aapMac));
268
269             String flowName = "Egress_DHCP_Client_v4" + dpId + "_" + lportTag + "_" + aapMac.getValue() + "_Permit_";
270             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY,
271                     "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
272         }
273     }
274
275     /**
276      * Add rule to ensure only DHCPv6 server traffic from the specified mac is
277      * allowed.
278      *
279      * @param dpId the dpid
280      * @param aapMacs the AAP mac addresses
281      * @param lportTag the lport tag
282      * @param addOrRemove whether to add or remove the flow
283      */
284     private void egressAclDhcpv6AllowClientTraffic(BigInteger dpId, Set<MacAddress> aapMacs, int lportTag,
285             int addOrRemove) {
286         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
287         for (MacAddress aapMac : aapMacs) {
288             List<MatchInfoBase> matches = new ArrayList<>();
289             matches.addAll(AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_CLIENT_PORT_IPV6,
290                 AclConstants.DHCP_SERVER_PORT_IPV6, lportTag, serviceMode));
291             matches.add(new MatchEthernetSource(aapMac));
292
293             String flowName = "Egress_DHCP_Client_v6" + "_" + dpId + "_" + lportTag + "_" + aapMac.getValue()
294                                     + "_Permit_";
295             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY,
296                     "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
297         }
298     }
299
300     /**
301      * Adds the rule to allow arp packets.
302      *
303      * @param dpId the dpId
304      * @param allowedAddresses the allowed addresses
305      * @param lportTag the lport tag
306      * @param addOrRemove whether to add or remove the flow
307      */
308     protected void programArpRule(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses, int lportTag,
309             int addOrRemove) {
310         for (AllowedAddressPairs allowedAddress : allowedAddresses) {
311             if (!AclServiceUtils.isIPv4Address(allowedAddress)) {
312                 continue; // For IPv6 allowed addresses
313             }
314
315             IpPrefixOrAddress allowedAddressIp = allowedAddress.getIpAddress();
316             MacAddress allowedAddressMac = allowedAddress.getMacAddress();
317             List<MatchInfoBase> arpIpMatches = AclServiceUtils.buildArpIpMatches(allowedAddressIp);
318             List<MatchInfoBase> matches = new ArrayList<>();
319             matches.add(MatchEthernetType.ARP);
320             matches.add(new MatchArpSha(allowedAddressMac));
321             matches.add(new MatchEthernetSource(allowedAddressMac));
322             matches.addAll(arpIpMatches);
323             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
324
325             List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
326             LOG.debug(addOrRemove == NwConstants.DEL_FLOW ? "Deleting " : "Adding " + "ARP Rule on DPID {}, "
327                     + "lportTag {}", dpId, lportTag);
328             String flowName = "Egress_ARP_" + dpId + "_" + lportTag + "_" + allowedAddress.getMacAddress().getValue()
329                     + String.valueOf(allowedAddressIp.getValue());
330             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, "ACL", 0,
331                     0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
332         }
333     }
334
335     /**
336      * Programs broadcast rules.
337      *
338      * @param port the Acl Interface port
339      * @param addOrRemove whether to delete or add flow
340      */
341     @Override
342     protected void programBroadcastRules(AclInterface port, int addOrRemove) {
343         programL2BroadcastAllowRule(port, addOrRemove);
344     }
345
346     /**
347      * Programs Non-IP broadcast rules.
348      *
349      * @param port the Acl Interface port
350      * @param addOrRemove whether to delete or add flow
351      */
352     private void programL2BroadcastAllowRule(AclInterface port, int addOrRemove) {
353         BigInteger dpId = port.getDpId();
354         int lportTag = port.getLPortTag();
355         List<AllowedAddressPairs> allowedAddresses = port.getAllowedAddressPairs();
356         Set<MacAddress> macs = allowedAddresses.stream().map(aap -> aap.getMacAddress()).collect(Collectors.toSet());
357         for (MacAddress mac : macs) {
358             List<MatchInfoBase> matches = new ArrayList<>();
359             matches.add(new MatchEthernetSource(mac));
360             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
361
362             List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
363
364             String flowName = "Egress_L2Broadcast_" + dpId + "_" + lportTag + "_" + mac.getValue();
365             syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_L2BROADCAST_TRAFFIC_MATCH_PRIORITY,
366                     "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
367         }
368     }
369
370     @Override
371     protected boolean isValidDirection(Class<? extends DirectionBase> direction) {
372         return direction.equals(DirectionEgress.class);
373     }
374
375     @Override
376     protected short getAclAntiSpoofingTable() {
377         return NwConstants.INGRESS_ACL_ANTI_SPOOFING_TABLE;
378     }
379
380     @Override
381     protected short getAclConntrackClassifierTable() {
382         return NwConstants.INGRESS_ACL_CONNTRACK_CLASSIFIER_TABLE;
383     }
384
385     @Override
386     protected short getAclConntrackSenderTable() {
387         return NwConstants.INGRESS_ACL_CONNTRACK_SENDER_TABLE;
388     }
389
390     @Override
391     protected short getAclForExistingTrafficTable() {
392         return NwConstants.INGRESS_ACL_FOR_EXISTING_TRAFFIC_TABLE;
393     }
394
395     @Override
396     protected short getAclFilterCumDispatcherTable() {
397         return NwConstants.INGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE;
398     }
399
400     @Override
401     protected short getAclRuleBasedFilterTable() {
402         return NwConstants.INGRESS_ACL_RULE_BASED_FILTER_TABLE;
403     }
404
405     @Override
406     protected short getAclRemoteAclTable() {
407         return NwConstants.INGRESS_REMOTE_ACL_TABLE;
408     }
409
410     @Override
411     protected short getAclCommitterTable() {
412         return NwConstants.INGRESS_ACL_COMMITTER_TABLE;
413     }
414 }