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