Merge "L2 Gw create changes related to ITM Tunnels creation in neutronvpn module"
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / IfmUtil.java
1 /*
2  * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. 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.vpnservice.interfacemgr;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future;
15
16 import com.google.common.base.Optional;
17
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.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
22 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
23 import org.opendaylight.vpnservice.interfacemgr.globals.VlanInterfaceInfo;
24 import org.opendaylight.vpnservice.interfacemgr.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
25 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
26 import org.opendaylight.vpnservice.mdsalutil.ActionType;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.write.metadata._case.WriteMetadata;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.*;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan.L2vlanMode;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
59 import org.opendaylight.yangtools.yang.binding.DataObject;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
62 import org.opendaylight.yangtools.yang.common.RpcResult;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 public class IfmUtil {
67     private static final Logger LOG = LoggerFactory.getLogger(IfmUtil.class);
68     private static final int INVALID_ID = 0;
69
70
71
72     public static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
73         /*
74          * NodeConnectorId is of form 'openflow:dpnid:portnum'
75          */
76         String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
77         return split[1];
78     }
79
80     public static BigInteger getDpnFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState){
81         NodeConnectorId ncId = getNodeConnectorIdFromInterface(ifState);
82         if(ncId != null){
83             return new BigInteger(getDpnFromNodeConnectorId(ncId));
84         }
85         return null;
86     }
87     public static String getPortNoFromInterfaceName(String ifaceName, DataBroker broker) {
88         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
89                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(ifaceName, broker);
90
91         String lowerLayerIf = ifState.getLowerLayerIf().get(0);
92         NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
93         String portNo = IfmUtil.getPortNoFromNodeConnectorId(nodeConnectorId);
94
95         return portNo;
96     }
97
98     public static String getPortNoFromNodeConnectorId(NodeConnectorId portId) {
99         /*
100          * NodeConnectorId is of form 'openflow:dpnid:portnum'
101          */
102         String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
103         return split[2];
104     }
105
106     public static NodeId buildDpnNodeId(BigInteger dpnId) {
107         return new NodeId(IfmConstants.OF_URI_PREFIX + dpnId);
108     }
109
110     public static InstanceIdentifier<Interface> buildId(String interfaceName) {
111         //TODO Make this generic and move to AbstractDataChangeListener or Utils.
112         InstanceIdentifierBuilder<Interface> idBuilder =
113                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
114         InstanceIdentifier<Interface> id = idBuilder.build();
115         return id;
116     }
117
118     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
119         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
120                 InstanceIdentifier.builder(InterfacesState.class)
121                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
122                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
123         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
124         return id;
125     }
126
127     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey getStateInterfaceKeyFromName(
128                     String name) {
129         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(name);
130     }
131
132     public static InstanceIdentifier<IdPool> getPoolId(String poolName){
133         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
134                         InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
135         InstanceIdentifier<IdPool> id = idBuilder.build();
136         return id;
137     }
138
139     public static List<String> getPortNameAndSuffixFromInterfaceName(String intfName) {
140         List<String> strList = new ArrayList<>(2);
141         int index = intfName.indexOf(":");
142         if (index != -1) {
143             strList.add(0, intfName.substring(0, index));
144             strList.add(1, intfName.substring(index));
145         }
146         return strList;
147     }
148
149     public static long getGroupId(long ifIndex, InterfaceInfo.InterfaceType infType) {
150         if (infType == InterfaceInfo.InterfaceType.LOGICAL_GROUP_INTERFACE) {
151             return ifIndex + IfmConstants.LOGICAL_GROUP_START;
152         }
153         else if (infType == InterfaceInfo.InterfaceType.VLAN_INTERFACE) {
154             return ifIndex + IfmConstants.VLAN_GROUP_START;
155         } else {
156             return ifIndex + IfmConstants.TRUNK_GROUP_START;
157         }
158     }
159
160     public static List<String> getDpIdPortNameAndSuffixFromInterfaceName(String intfName) {
161         List<String> strList = new ArrayList<>(3);
162         int index1 = intfName.indexOf(":");
163         if (index1 != -1) {
164             int index2 = intfName.indexOf(":", index1 + 1 );
165             strList.add(0, intfName.substring(0, index1));
166             if (index2 != -1) {
167                 strList.add(1, intfName.substring(index1, index2));
168                 strList.add(2, intfName.substring(index2));
169             } else {
170                 strList.add(1, intfName.substring(index1));
171                 strList.add(2, "");
172             }
173         }
174         return strList;
175     }
176
177     public static <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
178                                                           InstanceIdentifier<T> path, DataBroker broker) {
179
180         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
181
182         Optional<T> result = Optional.absent();
183         try {
184             result = tx.read(datastoreType, path).get();
185         } catch (Exception e) {
186             throw new RuntimeException(e);
187         }
188
189         return result;
190     }
191
192     public static List<Action> getEgressActionsForInterface(String interfaceName, Long tunnelKey, DataBroker dataBroker) {
193         List<ActionInfo> listActionInfo = getEgressActionInfosForInterface(interfaceName, tunnelKey, 0, dataBroker);
194         List<Action> actionsList = new ArrayList<>();
195         for (ActionInfo actionInfo : listActionInfo) {
196             actionsList.add(actionInfo.buildAction());
197         }
198         return actionsList;
199     }
200
201     public static List<ActionInfo> getEgressActionInfosForInterface(String     interfaceName,
202                                                                     int        actionKeyStart,
203                                                                     DataBroker dataBroker) {
204         return getEgressActionInfosForInterface(interfaceName, null, actionKeyStart, dataBroker);
205     }
206
207     /**
208      * Returns a list of Actions to be taken when sending a packet over an interface
209      *
210      * @param interfaceName
211      * @param tunnelKey Optional.
212      * @param actionKeyStart
213      * @param dataBroker
214      * @return
215      */
216     public static List<ActionInfo> getEgressActionInfosForInterface(String     interfaceName,
217                                                                     Long       tunnelKey,
218                                                                     int        actionKeyStart,
219                                                                     DataBroker dataBroker) {
220         List<ActionInfo> result = new ArrayList<ActionInfo>();
221         Interface interfaceInfo = InterfaceManagerCommonUtils.getInterfaceFromConfigDS(new InterfaceKey(interfaceName),
222                 dataBroker);
223         String portNo = IfmUtil.getPortNoFromInterfaceName(interfaceName, dataBroker);
224
225         InterfaceInfo.InterfaceType ifaceType = getInterfaceType(interfaceInfo);
226
227         switch (ifaceType ) {
228             case VLAN_INTERFACE:
229                 IfL2vlan vlanIface = interfaceInfo.getAugmentation(IfL2vlan.class);
230                 LOG.trace("L2Vlan: {}",vlanIface);
231                 boolean isVlanTransparent = false;
232                 long vlanVid = 0;
233                 if (vlanIface != null) {
234                     vlanVid = vlanIface.getVlanId() == null ? 0 : vlanIface.getVlanId().getValue();
235                     isVlanTransparent = vlanIface.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
236                 }
237                 if (vlanVid != 0 && !isVlanTransparent) {
238                     result.add(new ActionInfo(ActionType.push_vlan, new String[] {}, actionKeyStart));
239                     actionKeyStart++;
240                     result.add(new ActionInfo(ActionType.set_field_vlan_vid,
241                                new String[] { Long.toString(vlanVid) }, actionKeyStart));
242                     actionKeyStart++;
243                 }
244                 result.add(new ActionInfo(ActionType.output, new String[] {portNo}, actionKeyStart));
245                 actionKeyStart++;
246                 break;
247             case MPLS_OVER_GRE:
248             case VXLAN_TRUNK_INTERFACE:
249             case GRE_TRUNK_INTERFACE:
250                 if(tunnelKey != null) {
251                     result.add(new ActionInfo(ActionType.set_field_tunnel_id,
252                                                   new BigInteger[] { BigInteger.valueOf(tunnelKey.longValue()) },
253                                                   actionKeyStart) );
254                     actionKeyStart++;
255                 }
256
257                 result.add(new ActionInfo(ActionType.output, new String[] { portNo}, actionKeyStart));
258                 actionKeyStart++;
259                 break;
260
261             default:
262                 LOG.warn("Interface Type {} not handled yet", ifaceType);
263                 break;
264         }
265
266         return result;
267     }
268
269
270     public static NodeId getNodeIdFromNodeConnectorId(NodeConnectorId ncId) {
271         return new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
272     }
273
274     public static BigInteger[] mergeOpenflowMetadataWriteInstructions(List<Instruction> instructions) {
275         BigInteger metadata = new BigInteger("0", 16);
276         BigInteger metadataMask = new BigInteger("0", 16);
277         if (instructions != null && !instructions.isEmpty()) {
278             // check if metadata write instruction is present
279             for (Instruction instruction : instructions) {
280                 org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction actualInstruction = instruction.getInstruction();
281                 if (actualInstruction instanceof WriteMetadataCase) {
282                     WriteMetadataCase writeMetaDataInstruction = (WriteMetadataCase) actualInstruction ;
283                     WriteMetadata availableMetaData = writeMetaDataInstruction.getWriteMetadata();
284                     metadata = metadata.or(availableMetaData.getMetadata());
285                     metadataMask = metadataMask.or(availableMetaData.getMetadataMask());
286                 }
287             }
288         }
289         return new BigInteger[] { metadata, metadataMask };
290     }
291
292     public static Integer allocateId(IdManagerService idManager, String poolName, String idKey) {
293         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
294                 .setPoolName(poolName)
295                 .setIdKey(idKey).build();
296         try {
297             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
298             RpcResult<AllocateIdOutput> rpcResult = result.get();
299             if(rpcResult.isSuccessful()) {
300                 return rpcResult.getResult().getIdValue().intValue();
301             } else {
302                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
303             }
304         } catch (InterruptedException | ExecutionException e) {
305             LOG.warn("Exception when getting Unique Id",e);
306         }
307         return INVALID_ID;
308     }
309
310     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
311         ReleaseIdInput idInput = new ReleaseIdInputBuilder()
312                 .setPoolName(poolName)
313                 .setIdKey(idKey).build();
314         try {
315             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
316             RpcResult<Void> rpcResult = result.get();
317             if(!rpcResult.isSuccessful()) {
318                 LOG.warn("RPC Call to release Id {} with Key {} returned with Errors {}",
319                         idKey, rpcResult.getErrors());
320             }
321         } catch (InterruptedException | ExecutionException e) {
322             LOG.warn("Exception when releasing Id for key {}", idKey, e);
323         }
324     }
325
326     public static BigInteger getDpnId(DatapathId datapathId){
327         if (datapathId != null) {
328             // Adding logs for a random issue spotted during datapath id conversion
329             LOG.info("Received datapathId {}",datapathId.getValue());
330             String dpIdStr = datapathId.getValue().replace(":", "");
331             LOG.info("Received datapathId {}",dpIdStr);
332             BigInteger dpnId =  new BigInteger(dpIdStr, 16);
333             LOG.info("After conversion datapathId {}",dpnId);
334             return dpnId;
335         }
336         return null;
337     }
338
339     public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
340         return FlowBasedServicesUtils.getNodeConnectorIdFromInterface(iface, dataBroker);
341     }
342
343     public static String getPortName(DataBroker dataBroker, NodeConnectorId ncId){
344         InstanceIdentifier<NodeConnector> ncIdentifier =
345                 InstanceIdentifier.builder(Nodes.class)
346                         .child(Node.class, new NodeKey(getNodeIdFromNodeConnectorId(ncId)))
347                         .child(NodeConnector.class, new NodeConnectorKey(ncId)).build();
348         Optional<NodeConnector> optNc = read(LogicalDatastoreType.OPERATIONAL, ncIdentifier, dataBroker);
349         if(optNc.isPresent()) {
350             NodeConnector nc = optNc.get();
351             FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class);
352             return fcnc.getName();
353         }
354         return null;
355     }
356
357     public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState){
358         if(ifState != null) {
359             List<String> ofportIds = ifState.getLowerLayerIf();
360             return new NodeConnectorId(ofportIds.get(0));
361         }
362         return null;
363     }
364
365     public static InterfaceInfo.InterfaceType getInterfaceType(Interface iface) {
366         InterfaceInfo.InterfaceType interfaceType =
367                 org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType.UNKNOWN_INTERFACE;
368         Class<? extends org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType> ifType = iface.getType();
369
370         if (ifType.isAssignableFrom(L2vlan.class)) {
371             interfaceType =  org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType.VLAN_INTERFACE;
372         } else if (ifType.isAssignableFrom(Tunnel.class)) {
373             IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
374             Class<? extends  org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase> tunnelType = ifTunnel.getTunnelInterfaceType();
375             if (tunnelType.isAssignableFrom(TunnelTypeVxlan.class)) {
376                 interfaceType = InterfaceInfo.InterfaceType.VXLAN_TRUNK_INTERFACE;
377             } else if (tunnelType.isAssignableFrom(TunnelTypeGre.class)) {
378                 interfaceType = InterfaceInfo.InterfaceType.GRE_TRUNK_INTERFACE;
379             } else if(tunnelType.isAssignableFrom(TunnelTypeMplsOverGre.class)){
380                 interfaceType = InterfaceInfo.InterfaceType.MPLS_OVER_GRE;
381             }
382         }
383         // TODO: Check if the below condition is still needed/valid
384         //else if (ifType.isAssignableFrom(InterfaceGroup.class)) {
385         //    interfaceType =  org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType.LOGICAL_GROUP_INTERFACE;
386         //}
387         return interfaceType;
388     }
389
390     public static VlanInterfaceInfo getVlanInterfaceInfo(String interfaceName, Interface iface, BigInteger dpId){
391         IfL2vlan vlanIface = iface.getAugmentation(IfL2vlan.class);
392
393         short vlanId = 0;
394         //FIXME :Use this below thing properly
395         VlanInterfaceInfo vlanInterfaceInfo = new VlanInterfaceInfo(dpId, "someString", vlanId);
396
397         if (vlanIface != null) {
398             vlanId = vlanIface.getVlanId() == null ? 0 : vlanIface.getVlanId().getValue().shortValue();
399             L2vlanMode l2VlanMode = vlanIface.getL2vlanMode();
400
401             if (l2VlanMode == L2vlanMode.Transparent) {
402                 vlanInterfaceInfo.setVlanTransparent(true);
403             }
404             if (l2VlanMode == L2vlanMode.NativeUntagged) {
405                 vlanInterfaceInfo.setUntaggedVlan(true);
406             }
407             vlanInterfaceInfo.setVlanId(vlanId);
408
409         }
410         return vlanInterfaceInfo;
411     }
412 }