Merge "Fixed NPO and and some other changes"
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / utils / AclServiceUtils.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.aclservice.utils;
10
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.MatchFieldType;
24 import org.opendaylight.genius.mdsalutil.MatchInfo;
25 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
26 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
29 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
30 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
63 import org.opendaylight.yangtools.yang.binding.DataObject;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 public class AclServiceUtils {
71
72     private static final Logger LOG = LoggerFactory.getLogger(AclServiceUtils.class);
73
74     private AclServiceUtils() { }
75
76     /**
77      * Retrieves the Interface from the datastore.
78      * @param broker the data broker
79      * @param interfaceName the interface name
80      * @return the interface.
81      */
82     public static Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
83         .Interface> getInterface(DataBroker broker, String interfaceName) {
84         return read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
85     }
86
87     /**
88      * Builds the interface identifier.
89      * @param interfaceName the interface name.
90      * @return the interface identifier.
91      */
92     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
93         .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
94         return InstanceIdentifier.builder(Interfaces.class)
95                 .child(
96                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
97                     .Interface.class, new InterfaceKey(interfaceName)).build();
98     }
99
100     /**
101      * Retrieves the object from the datastore.
102      * @param broker the data broker.
103      * @param datastoreType the data store type.
104      * @param path the wild card path.
105      * @return the required object.
106      */
107     public static <T extends DataObject> Optional<T> read(
108             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
109
110         Optional<T> result = Optional.absent();
111         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
112         try {
113             result = tx.read(datastoreType, path).checkedGet();
114         } catch (ReadFailedException e) {
115             LOG.warn("Failed to read InstanceIdentifier {} from {}", path, datastoreType, e);
116         } finally {
117             tx.close();
118         }
119         return result;
120     }
121
122     /**
123      * Retrieves the acl matching the key from the data store.
124      *
125      * @param broker the data broker
126      * @param aclKey the acl key
127      * @return the acl
128      */
129     public static Acl getAcl(DataBroker broker, String aclKey) {
130         Optional<Acl> optAcl = read(broker,
131             LogicalDatastoreType.CONFIGURATION, getAclInstanceIdentifier(aclKey));
132         if (optAcl.isPresent()) {
133             return optAcl.get();
134         }
135         return null;
136     }
137
138     /** Creates the Acl instance identifier.
139      *
140      * @param aclKey the acl key
141      * @return the instance identifier
142      */
143     public static InstanceIdentifier<Acl> getAclInstanceIdentifier(String aclKey) {
144         return InstanceIdentifier
145                 .builder(AccessLists.class)
146                 .child(Acl.class,
147                         new AclKey(aclKey,Ipv4Acl.class))
148                 .build();
149     }
150
151     /**
152      * Get the data path number for the interface.
153      * @param interfaceManagerRpcService interfaceManagerRpcService instance.
154      * @param ifName the interface name.
155      * @return the dpn.
156      */
157     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
158         BigInteger nodeId = BigInteger.ZERO;
159         try {
160             GetDpidFromInterfaceInput dpIdInput =
161                     new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
162             Future<RpcResult<GetDpidFromInterfaceOutput>> dpIdOutput =
163                     interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
164             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
165             if (dpIdResult.isSuccessful()) {
166                 nodeId = dpIdResult.getResult().getDpid();
167             } else {
168                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
169             }
170         } catch (NullPointerException | InterruptedException | ExecutionException e) {
171             LOG.error("Exception when getting dpn for interface {}", ifName,  e);
172         }
173         return nodeId;
174     }
175
176     /**
177      * Retrieves the interface state.
178      * @param dataBroker the data broker.
179      * @param interfaceName the interface name.
180      * @return the interface state.
181      */
182     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
183         .Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
184         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
185             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
186         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
187             .interfaces.state.Interface> ifStateOptional = MDSALUtil.read(LogicalDatastoreType
188                 .OPERATIONAL, ifStateId, dataBroker);
189         if (!ifStateOptional.isPresent()) {
190             return null;
191         }
192
193         return ifStateOptional.get();
194     }
195
196     /**
197      * Build the interface state.
198      * @param interfaceName the interface name.
199      * @return the interface state.
200      */
201     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
202         .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
203         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
204             .interfaces.state.Interface> idBuilder = InstanceIdentifier.builder(InterfacesState.class)
205             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
206             .state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
207             .rev140508.interfaces.state.InterfaceKey(interfaceName));
208         return idBuilder.build();
209     }
210
211     /**
212      * Checks whether port security is enabled for the port.
213      * @param port the port.
214      * @return the port security is enabled/not.
215      */
216     public static boolean isPortSecurityEnabled(Interface port) {
217         if (port == null) {
218             LOG.error("Port is Null");
219             return false;
220         }
221         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
222         if (aclInPort == null) {
223             LOG.error("getSecurityGroupInPortList: no security group associated to Interface port: {}", port.getName());
224             return false;
225         }
226         return aclInPort.isPortSecurityEnabled();
227     }
228
229     /**
230      * Checks whether port security is enabled for the port.
231      * @param port the port.
232      * @return the list of security groups.
233      */
234     public static List<Uuid> getInterfaceAcls(Interface port) {
235         if (port == null) {
236             LOG.error("Port is Null");
237             return null;
238         }
239         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
240         if (aclInPort == null) {
241             LOG.error("getSecurityGroupInPortList: no security group associated}",
242                 port.getName());
243             return null;
244         }
245         return aclInPort.getSecurityGroups();
246     }
247
248     /**
249      * Retrieves the security rule attribute augmentation from the access list.
250      * @param ace the access list entry
251      * @return the security rule attributes
252      */
253     public static SecurityRuleAttr  getAccesssListAttributes(Ace ace) {
254         if (ace == null) {
255             LOG.error("Ace is Null");
256             return null;
257         }
258         SecurityRuleAttr aceAttributes = ace.getAugmentation(SecurityRuleAttr.class);
259         if (aceAttributes == null) {
260             LOG.error("Ace is null");
261             return null;
262         }
263         return aceAttributes;
264     }
265
266     /**
267      * Returns the DHCP match.
268      * @param srcPort the source port.
269      * @param dstPort the destination port.
270      * @return list of matches.
271      */
272     private static List<MatchInfoBase> buildDhcpMatches(int srcPort, int dstPort, MatchInfo portMatch) {
273         List<MatchInfoBase> matches = new ArrayList<>(6);
274         matches.add(new MatchInfo(MatchFieldType.eth_type,
275                 new long[] { NwConstants.ETHTYPE_IPV4 }));
276         matches.add(new MatchInfo(MatchFieldType.ip_proto,
277                 new long[] { IPProtocols.UDP.intValue() }));
278         matches.add(new MatchInfo(MatchFieldType.udp_dst,
279                 new long[] { srcPort }));
280         matches.add(new MatchInfo(MatchFieldType.udp_src,
281                 new long[] { dstPort}));
282         matches.add(portMatch);
283         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state,
284                 new long[] { AclConstants.TRACKED_NEW_CT_STATE, AclConstants.TRACKED_NEW_CT_STATE_MASK}));
285         return matches;
286     }
287
288     /**
289      * Builds a list of matches for DHCP filtering on the source's MAC address.
290      *
291      * @param srcPort The source port.
292      * @param dstPort The destination port.
293      * @param attachMac The attached port's MAC address.
294      *
295      * @return The matches.
296      */
297     public static List<MatchInfoBase> buildDhcpSourceMatches(int srcPort, int dstPort, String attachMac) {
298         return buildDhcpMatches(srcPort, dstPort, new MatchInfo(MatchFieldType.eth_src, new String[] { attachMac }));
299     }
300
301     /**
302      * Builds a list of matches for DHCP filtering on the destination's MAC address.
303      *
304      * @param srcPort The source port.
305      * @param dstPort The destination port.
306      * @param attachMac The attached port's MAC address.
307      *
308      * @return The matches.
309      */
310     public static List<MatchInfoBase> buildDhcpDestinationMatches(int srcPort, int dstPort, String attachMac) {
311         return buildDhcpMatches(srcPort, dstPort, new MatchInfo(MatchFieldType.eth_dst, new String[] { attachMac }));
312     }
313
314     /**
315      * Builds the service id.
316      *
317      * @param interfaceName the interface name
318      * @param serviceIndex the service index
319      * @param serviceMode the service mode
320      * @return the instance identifier
321      */
322     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
323             Class<? extends ServiceModeBase> serviceMode) {
324         return InstanceIdentifier.builder(ServiceBindings.class)
325                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
326                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
327     }
328
329     /**
330      * Gets the bound services.
331      *
332      * @param serviceName the service name
333      * @param servicePriority the service priority
334      * @param flowPriority the flow priority
335      * @param cookie the cookie
336      * @param instructions the instructions
337      * @return the bound services
338      */
339     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
340             BigInteger cookie, List<Instruction> instructions) {
341         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
342                 .setInstruction(instructions);
343         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
344                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
345                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
346     }
347
348     public static List<Uuid> getUpdatedAclList(Interface updatedPort, Interface currentPort) {
349         if (updatedPort == null) {
350             return null;
351         }
352         List<Uuid> updatedAclList = new ArrayList<>(AclServiceUtils.getInterfaceAcls(updatedPort));
353         if (currentPort == null) {
354             return updatedAclList;
355         }
356         List<Uuid> currentAclList = new ArrayList<>(AclServiceUtils.getInterfaceAcls(currentPort));
357         for (Iterator<Uuid> iterator = updatedAclList.iterator(); iterator.hasNext();) {
358             Uuid updatedAclUuid = iterator.next();
359             for (Uuid currentAclUuid :currentAclList) {
360                 if (updatedAclUuid.getValue().equals(currentAclUuid.getValue())) {
361                     iterator.remove();
362                 }
363             }
364         }
365         return updatedAclList;
366     }
367
368     public static List<AllowedAddressPairs> getUpdatedAllowedAddressPairs(Interface updatedPort,
369             Interface currentPort) {
370         if (updatedPort == null) {
371             return null;
372         }
373         List<AllowedAddressPairs> updatedAllowedAddressPairs =
374                 new ArrayList<>(AclServiceUtils.getPortAllowedAddresses(updatedPort));
375         if (currentPort == null) {
376             return updatedAllowedAddressPairs;
377         }
378         List<AllowedAddressPairs> currentAllowedAddressPairs =
379                 new ArrayList<>(AclServiceUtils.getPortAllowedAddresses(currentPort));
380         for (Iterator<AllowedAddressPairs> iterator = updatedAllowedAddressPairs.iterator(); iterator.hasNext();) {
381             AllowedAddressPairs updatedAllowedAddressPair = iterator.next();
382             for (AllowedAddressPairs currentAllowedAddressPair : currentAllowedAddressPairs) {
383                 if (updatedAllowedAddressPair.getKey().equals(currentAllowedAddressPair.getKey())) {
384                     iterator.remove();
385                     break;
386                 }
387             }
388         }
389         return updatedAllowedAddressPairs;
390     }
391
392     public static List<AllowedAddressPairs> getPortAllowedAddresses(Interface port) {
393         if (port == null) {
394             LOG.error("Port is Null");
395             return null;
396         }
397         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
398         if (aclInPort == null) {
399             LOG.error("getSecurityGroupInPortList: no security group associated to Interface port: {}", port.getName());
400             return null;
401         }
402         return aclInPort.getAllowedAddressPairs();
403     }
404
405     public static BigInteger getDpIdFromIterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
406             .interfaces.rev140508.interfaces.state.Interface interfaceState) {
407         BigInteger dpId = null;
408         String interfaceName = interfaceState.getName();
409         List<String> ofportIds = interfaceState.getLowerLayerIf();
410         if (ofportIds != null && !ofportIds.isEmpty()) {
411             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
412             dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
413         }
414         return dpId;
415     }
416
417     public static List<MatchInfoBase> getAllowedIpMatches(IpPrefixOrAddress allowedIp, MatchFieldType ipv4MatchType) {
418         List<MatchInfoBase> flowMatches = new ArrayList<>();
419         flowMatches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
420         IpPrefix ipPrefix = allowedIp.getIpPrefix();
421         if (ipPrefix != null) {
422             if (ipPrefix.getIpv4Prefix().getValue() != null) {
423                 String[] ipaddressValues = ipPrefix.getIpv4Prefix().getValue().split("/");
424                 flowMatches.add(new MatchInfo(ipv4MatchType, new String[] {ipaddressValues[0], ipaddressValues[1]}));
425             } else {
426                 // Handle IPv6
427             }
428         } else {
429             IpAddress ipAddress = allowedIp.getIpAddress();
430             if (ipAddress.getIpv4Address() != null) {
431                 flowMatches.add(new MatchInfo(ipv4MatchType,
432                         new String[] {ipAddress.getIpv4Address().getValue(), "32"}));
433             } else {
434                 // Handle IPv6
435             }
436         }
437         return flowMatches;
438     }
439
440     public static List<MatchInfo> getLPortTagMatches(int lportTag) {
441         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
442         // Matching metadata
443         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
444             MetaDataUtil.getLportTagMetaData(lportTag),
445             MetaDataUtil.METADATA_MASK_LPORT_TAG }));
446         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(lportTag)}));
447         return mkMatches;
448     }
449 }