Bug 5229 : ElanInterfaceName should not follow the portName:vlanId format
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
1 /*
2  * Copyright (c) 2015 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.servicebindings.flowbased.utilities;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.List;
15
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.vpnservice.interfacemgr.IfmConstants;
20 import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
21 import org.opendaylight.vpnservice.interfacemgr.commons.InterfaceManagerCommonUtils;
22 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
23 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
24 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
25 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
26 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL2vlan;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.google.common.base.Optional;
54
55 public class FlowBasedServicesUtils {
56     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
57
58     public static ServicesInfo getServicesInfoForInterface(String interfaceName, DataBroker dataBroker) {
59         ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName);
60         InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
61                 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
62         Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
63                 servicesInfoIdentifierBuilder.build(), dataBroker);
64
65         if (servicesInfoOptional.isPresent()) {
66             return servicesInfoOptional.get();
67         }
68
69         return null;
70     }
71
72     public static NodeConnectorId getNodeConnectorIdFromInterface(Interface iface, DataBroker dataBroker) {
73         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
74                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(iface.getName(), dataBroker);
75         if(ifState != null) {
76             List<String> ofportIds = ifState.getLowerLayerIf();
77             return new NodeConnectorId(ofportIds.get(0));
78         }
79         return null;
80     }
81
82     public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
83         List<MatchInfo> matches = new ArrayList<>();
84         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
85         int vlanId = 0;
86         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
87         if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
88             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
89         }
90         if (vlanId > 0) {
91             matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
92         }
93         return matches;
94     }
95
96     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
97         List<MatchInfo> matches = new ArrayList<MatchInfo>();
98         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
99         return matches;
100     }
101
102     public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, Interface iface,
103                                                                  int interfaceTag, short servicePriority) {
104         List<MatchInfo> matches = new ArrayList<MatchInfo>();
105         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
106                 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
107                 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
108         return matches;
109     }
110
111     public static Long getLPortTag(Interface iface, DataBroker dataBroker) {
112         /*ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
113         String portName = parentRefs.getParentInterface();
114         BigInteger dpIdFromInterface = parentRefs.getDatapathNodeIdentifier();
115         String portKey = FlowBasedServicesUtils.getInterfaceRefInfo(dpIdFromInterface.toString(), portName);
116         if (iface.getType().isAssignableFrom(L2vlan.class)) {
117             InterfacesMetaKey interfacesMetaKey = new InterfacesMetaKey(portKey);
118             InterfacesInfoKey interfacesInfoKey = new InterfacesInfoKey(iface.getName());
119             InterfacesInfo interfacesInfo = VlanInterfaceUtilities.getInterfacesInfoFromConfigDS(interfacesMetaKey,
120                     interfacesInfoKey, dataBroker);
121             return interfacesInfo.getLporttag();
122         } else if (iface.getType().isAssignableFrom(Tunnel.class)) {
123             TunnelInterfaceRefInfoKey tunnelInterfaceRefInfoKey = new TunnelInterfaceRefInfoKey(portKey);
124             TunnelInterfaceEntries tunnelInterfaceEntries =
125                     TunnelInterfaceUtilities.getTunnelInterfaceRefEntriesFromConfigDs(
126                             tunnelInterfaceRefInfoKey, iface.getName(), dataBroker);
127             return tunnelInterfaceEntries.getLportTag();
128         } */
129         return 0L;
130     }
131
132     public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
133                                                    BoundServices boundServiceNew,
134                                                    WriteTransaction t,
135                                                    List<MatchInfo> matches, int lportTag, short tableId) {
136         List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
137
138         int serviceInstructionsSize = instructions.size();
139         List<Instruction> instructionSet = new ArrayList<Instruction>();
140         int vlanId = 0;
141         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
142         if(l2vlan != null && l2vlan.getVlanId() != null){
143             vlanId = l2vlan.getVlanId().getValue();
144         }
145         if (vlanId != 0) {
146             // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
147             int actionKey = ++serviceInstructionsSize;
148             instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
149         }
150
151         if (lportTag != 0L) {
152             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
153             short sIndex = boundServiceNew.getServicePriority();
154             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
155                     ++sIndex, metadataValues[0]);
156             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
157                     MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
158                     MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
159             instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
160                     ++serviceInstructionsSize));
161         }
162
163         if (instructions != null && !instructions.isEmpty()) {
164             for (Instruction info : instructions) {
165                 // Skip meta data write as that is handled already
166                 if (info.getInstruction() instanceof WriteMetadataCase) {
167                     continue;
168                 }
169                 instructionSet.add(info);
170             }
171         }
172
173         String serviceRef = boundServiceNew.getServiceName();
174         String flowRef = getFlowRef(dpId, iface.getName(), boundServiceNew, boundServiceNew.getServicePriority());
175         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
176         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
177                 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
178                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
179         installFlow(dpId, ingressFlow, t);
180     }
181
182     public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
183         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
184         Node nodeDpn = buildInventoryDpnNode(dpId);
185         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
186                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
187                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
188
189         t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
190     }
191
192     public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
193         LOG.debug("Removing Ingress Flows");
194         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
195         Node nodeDpn = buildInventoryDpnNode(dpId);
196         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
197                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
198                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
199
200         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
201     }
202
203     private static Node buildInventoryDpnNode(BigInteger dpnId) {
204         NodeId nodeId = new NodeId("openflow:" + dpnId);
205         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
206
207         return nodeDpn;
208     }
209
210     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, Interface iface,
211                                                   WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
212         LOG.debug("Installing LPort Dispatcher Flows {}, {}", dpId, iface);
213         String serviceRef = boundService.getServiceName();
214         List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, iface,
215                 interfaceTag, currentServiceIndex);
216
217         // Get the metadata and mask from the service's write metadata instruction
218         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
219         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
220         int instructionSize = serviceInstructions.size();
221         BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
222         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
223         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
224                 MetaDataUtil.METADATA_MASK_LPORT_TAG, metadataValues[1]);
225
226         // build the final instruction for LPort Dispatcher table flow entry
227         List<Instruction> instructions = new ArrayList<Instruction>();
228         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
229         if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
230             for (Instruction info : serviceInstructions) {
231                 // Skip meta data write as that is handled already
232                 if (info.getInstruction() instanceof WriteMetadataCase) {
233                     continue;
234                 }
235                 instructions.add(info);
236             }
237         }
238
239         // build the flow and install it
240         String flowRef = getFlowRef(dpId, iface.getName(), boundService, currentServiceIndex);
241         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
242                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
243         installFlow(dpId, ingressFlow, t);
244     }
245
246     public static void removeIngressFlow(Interface iface, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
247         LOG.debug("Removing Ingress Flows");
248         String flowKeyStr = getFlowRef(dpId, iface.getName(), serviceOld, serviceOld.getServicePriority());
249         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
250         Node nodeDpn = buildInventoryDpnNode(dpId);
251         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
252                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
253                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
254
255         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
256     }
257
258     public static void removeLPortDispatcherFlow(BigInteger dpId, Interface iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
259         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
260
261         StypeOpenflow stypeOpenFlow = boundServicesOld.getAugmentation(StypeOpenflow.class);
262         // build the flow and install it
263         String flowRef = getFlowRef(dpId, iface.getName(), boundServicesOld, currentServiceIndex);
264         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
265         Node nodeDpn = buildInventoryDpnNode(dpId);
266         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
267                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
268                 .child(Table.class, new TableKey(stypeOpenFlow.getDispatcherTableId())).child(Flow.class, flowKey).build();
269
270         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
271     }
272
273     private static String getFlowRef(BigInteger dpnId, String iface, BoundServices service, short currentServiceIndex) {
274         return new StringBuffer().append(dpnId).append(NwConstants.VLAN_INTERFACE_INGRESS_TABLE).append(NwConstants.FLOWID_SEPARATOR)
275                 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
276     }
277
278     /**
279      * This util method returns an array of ServiceInfo in which index 0 will
280      * have the immediate lower priority service and index 1 will have the
281      * immediate higher priority service among the list of existing serviceInfos
282      *
283      * @param serviceInfos
284      * @param currentServiceInfo
285      * @return
286      */
287  public static BoundServices[] getHighAndLowPriorityService(
288             List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
289     BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
290     BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
291         if (serviceInfos == null || serviceInfos.isEmpty()) {
292             return new BoundServices[]{lower, higher};
293         }
294         List <BoundServices> availableServiceInfos = new ArrayList<BoundServices>(serviceInfos);
295         Collections.sort(availableServiceInfos, new Comparator<BoundServices>() {
296             @Override
297             public int compare(BoundServices serviceInfo1, BoundServices serviceInfo2) {
298                 return serviceInfo2.getServicePriority().compareTo(serviceInfo1.getServicePriority());
299             }
300         });
301         for (BoundServices availableServiceInfo: availableServiceInfos) {
302             if (currentServiceInfo.getServicePriority() > availableServiceInfo.getServicePriority()) {
303                 lower = availableServiceInfo;
304                 break;
305             } else {
306                 higher = availableServiceInfo;
307             }
308         }
309         return new BoundServices[]{lower,higher};
310     }
311
312     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
313         List <BoundServices> availableServiceInfos = new ArrayList<BoundServices>(serviceInfos);
314         if (availableServiceInfos.isEmpty()) {
315             return null;
316         }
317         BoundServices highPriorityService = availableServiceInfos.get(0);
318         availableServiceInfos.remove(0);
319         for (BoundServices availableServiceInfo: availableServiceInfos) {
320             if (availableServiceInfo.getServicePriority() > highPriorityService.getServicePriority()) {
321                 highPriorityService = availableServiceInfo;
322             }
323         }
324         return highPriorityService;
325     }
326
327     public static void installVlanFlow(BigInteger dpId, long portNo, Interface iface, 
328             WriteTransaction t, List<MatchInfo> matches, int lportTag) {
329         int vlanId = 0;
330         boolean isVlanTransparent = false;
331         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
332         if(l2vlan != null){
333             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
334             isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
335         }
336         int instructionKey = 0;
337         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0);
338         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher();
339         List<Instruction> instructions = new ArrayList<Instruction>();
340         if (vlanId != 0 && !isVlanTransparent) {
341             instructions.add(MDSALUtil.buildAndGetPopVlanActionInstruction(lportTag, instructionKey++));
342         }
343         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
344         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.DHCP_TABLE, instructionKey++));
345         int priority =  isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
346         String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
347         Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
348                 IfmConstants.VLAN_TABLE_COOKIE, matches, instructions);
349         installFlow(dpId, ingressFlow, t);
350 }
351
352     public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
353         return String.format("%d:%s:%s", tableId, dpnId, infName);
354     }
355
356     public static void removeIngressFlow(String interfaceName, BigInteger dpId, WriteTransaction t) {
357         LOG.debug("Removing Ingress Flows");
358         String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
359         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
360         Node nodeDpn = buildInventoryDpnNode(dpId);
361         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
362                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
363                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
364
365         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
366     }
367
368
369 }