Merge "Fix cpu hog in JobQueueHandler thread"
[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 com.google.common.util.concurrent.ListenableFuture;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.interfacemanager.IfmConstants;
22 import org.opendaylight.genius.interfacemanager.IfmUtil;
23 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
24 import org.opendaylight.genius.mdsalutil.*;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.WriteMetadataCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.*;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class FlowBasedServicesUtils {
53     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
54
55     public enum ServiceMode  {
56         INGRESS,
57         EGRESS;
58     }
59
60     public static final ImmutableBiMap SERVICE_MODE_MAP =
61             new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
62                     .put(ServiceMode.EGRESS, ServiceModeEgress.class)
63                     .put(ServiceMode.INGRESS, ServiceModeIngress.class)
64                     .build();
65
66     public static ServicesInfo getServicesInfoForInterface(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
67                                                            DataBroker dataBroker) {
68         ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName,serviceMode);
69         InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
70                 InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
71         Optional<ServicesInfo> servicesInfoOptional = IfmUtil.read(LogicalDatastoreType.CONFIGURATION,
72                 servicesInfoIdentifierBuilder.build(), dataBroker);
73
74         if (servicesInfoOptional.isPresent()) {
75             return servicesInfoOptional.get();
76         }
77
78         return null;
79     }
80
81     public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
82         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
83                 InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
84         if(ifState != null) {
85             List<String> ofportIds = ifState.getLowerLayerIf();
86             return new NodeConnectorId(ofportIds.get(0));
87         }
88         return null;
89     }
90
91     public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
92         if(ifState != null) {
93             List<String> ofportIds = ifState.getLowerLayerIf();
94             return new NodeConnectorId(ofportIds.get(0));
95         }
96         return null;
97     }
98
99     public static BigInteger getDpnIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
100         NodeConnectorId nodeConnectorId = null;
101         if(ifState != null) {
102             List<String> ofportIds = ifState.getLowerLayerIf();
103             nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
104         }
105         return new BigInteger(IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId));
106     }
107
108     public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
109         List<MatchInfo> matches = new ArrayList<>();
110         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
111         int vlanId = 0;
112         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
113         if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
114             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
115         }
116         if (vlanId > 0) {
117             matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
118         }
119         return matches;
120     }
121
122     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
123         List<MatchInfo> matches = new ArrayList<>();
124         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
125         return matches;
126     }
127
128     public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId,
129                                                                  int interfaceTag, short servicePriority) {
130         List<MatchInfo> matches = new ArrayList<>();
131         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
132                 MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
133                 MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
134         return matches;
135     }
136
137     public static List<NxMatchInfo> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
138         List<NxMatchInfo> matches = new ArrayList<>();
139         matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] {
140                 MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)}));
141         return matches;
142     }
143
144     public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
145                                                    BoundServices boundServiceNew,
146                                                    WriteTransaction t,
147                                                    List<MatchInfo> matches, int lportTag, short tableId) {
148         List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
149
150         int serviceInstructionsSize = instructions.size();
151         List<Instruction> instructionSet = new ArrayList<>();
152         int vlanId = 0;
153         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
154         if(l2vlan != null && l2vlan.getVlanId() != null){
155             vlanId = l2vlan.getVlanId().getValue();
156         }
157         if (vlanId != 0) {
158             // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
159             int actionKey = ++serviceInstructionsSize;
160             instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
161         }
162
163         if (lportTag != 0L) {
164             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
165             short sIndex = boundServiceNew.getServicePriority();
166             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
167                     ++sIndex, metadataValues[0], isExternal(iface));
168             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
169                     MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
170                     MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG, metadataValues[1]);
171             instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
172                     ++serviceInstructionsSize));
173         }
174
175         if (instructions != null && !instructions.isEmpty()) {
176             for (Instruction info : instructions) {
177                 // Skip meta data write as that is handled already
178                 if (info.getInstruction() instanceof WriteMetadataCase) {
179                     continue;
180                 }
181                 instructionSet.add(info);
182             }
183         }
184
185         String serviceRef = boundServiceNew.getServiceName();
186         String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
187                 boundServiceNew, boundServiceNew.getServicePriority());
188         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
189         Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
190                 stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
191                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
192         installFlow(dpId, ingressFlow, t);
193     }
194
195     public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
196         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
197         Node nodeDpn = buildInventoryDpnNode(dpId);
198         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
199                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
200                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
201
202         t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
203     }
204
205     public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
206         LOG.debug("Removing Ingress Flows");
207         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
208         Node nodeDpn = buildInventoryDpnNode(dpId);
209         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
210                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
211                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
212
213         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
214     }
215
216     private static Node buildInventoryDpnNode(BigInteger dpnId) {
217         NodeId nodeId = new NodeId("openflow:" + dpnId);
218         Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
219
220         return nodeDpn;
221     }
222
223     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
224                                                   WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
225         LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
226         String serviceRef = boundService.getServiceName();
227         List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId,
228                 interfaceTag, currentServiceIndex);
229
230         // Get the metadata and mask from the service's write metadata instruction
231         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
232         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
233         int instructionSize = serviceInstructions.size();
234         BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
235         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
236         BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
237
238         // build the final instruction for LPort Dispatcher table flow entry
239         List<Instruction> instructions = new ArrayList<>();
240         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
241         if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
242             for (Instruction info : serviceInstructions) {
243                 // Skip meta data write as that is handled already
244                 if (info.getInstruction() instanceof WriteMetadataCase) {
245                     continue;
246                 }
247                 instructions.add(info);
248             }
249         }
250
251         // build the flow and install it
252         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
253         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
254                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
255         installFlow(dpId, ingressFlow, t);
256     }
257
258     public static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
259                                                   WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
260         LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
261         String serviceRef = boundService.getServiceName();
262         List<? extends MatchInfoBase> matches;
263         matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
264
265         // Get the metadata and mask from the service's write metadata instruction
266         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
267         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
268         int instructionSize = serviceInstructions.size();
269
270         // build the final instruction for LPort Dispatcher table flow entry
271         List<Instruction> instructions = new ArrayList<Instruction>();
272         if(boundService.getServicePriority() != NwConstants.DEFAULT_EGRESS_SERVICE_INDEX) {
273             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
274             BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
275             BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
276             instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
277             instructions.add(MDSALUtil.buildAndGetSetReg6ActionInstruction(0, ++instructionSize, 0, 31,
278                     MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
279         }
280         if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
281             for (Instruction info : serviceInstructions) {
282                 // Skip meta data write as that is handled already
283                 if (info.getInstruction() instanceof WriteMetadataCase) {
284                     continue;
285                 }
286                 instructions.add(info);
287             }
288         }
289
290         // build the flow and install it
291         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
292         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
293                 boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
294         installFlow(dpId, ingressFlow, t);
295     }
296
297
298     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
299                                                  BigInteger cookie, List<Instruction> instructions) {
300         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
301         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
302                 .setServiceName(serviceName).setServicePriority(servicePriority)
303                 .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
304     }
305
306     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
307         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
308                 new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
309                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
310     }
311
312     public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName) {
313         IfmUtil.unbindService(dataBroker, interfaceName, buildServiceId(interfaceName, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
314                 ServiceModeEgress.class);
315     }
316
317     public static void bindDefaultEgressDispatcherService(Interface interfaceInfo, String portNo, String interfaceName,
318                                                           WriteTransaction tx, int ifIndex) {
319         int priority = NwConstants.DEFAULT_EGRESS_SERVICE_INDEX;
320         List<Instruction> instructions = IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex);
321         BoundServices
322                 serviceInfo =
323                 getBoundServices(String.format("%s.%s", "default", interfaceName),
324                         NwConstants.DEFAULT_EGRESS_SERVICE_INDEX, priority,
325                         NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
326         IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
327     }
328
329     public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
330         LOG.debug("Removing Ingress Flows");
331         String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld, serviceOld.getServicePriority());
332         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
333         Node nodeDpn = buildInventoryDpnNode(dpId);
334         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
335                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
336                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
337
338         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
339     }
340
341     public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
342         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
343
344         boundServicesOld.getAugmentation(StypeOpenflow.class);
345         // build the flow and install it
346         String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
347         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
348         Node nodeDpn = buildInventoryDpnNode(dpId);
349         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
350                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
351                 .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
352
353         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
354     }
355
356     public static void removeEgressDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
357         LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
358         // build the flow and install it
359         String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
360         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
361         Node nodeDpn = buildInventoryDpnNode(dpId);
362         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
363                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
364                 .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
365
366         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
367     }
368
369     private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service, short currentServiceIndex) {
370         return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
371                 .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(currentServiceIndex).toString();
372     }
373
374     /**
375      * This util method returns an array of ServiceInfo in which index 0 will
376      * have the immediate lower priority service and index 1 will have the
377      * immediate higher priority service among the list of existing serviceInfos
378      *
379      * @param serviceInfos
380      * @param currentServiceInfo
381      * @return
382      */
383     public static BoundServices[] getHighAndLowPriorityService(
384             List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
385         BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
386         BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
387         if (serviceInfos == null || serviceInfos.isEmpty()) {
388             return new BoundServices[]{lower, higher};
389         }
390         List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
391         Collections.sort(availableServiceInfos, new Comparator<BoundServices>() {
392             @Override
393             public int compare(BoundServices serviceInfo1, BoundServices serviceInfo2) {
394                 return serviceInfo1.getServicePriority().compareTo(serviceInfo2.getServicePriority());
395             }
396         });
397         for (BoundServices availableServiceInfo: availableServiceInfos) {
398             if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
399                 lower = availableServiceInfo;
400                 break;
401             } else {
402                 higher = availableServiceInfo;
403             }
404         }
405         return new BoundServices[]{lower,higher};
406     }
407
408     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
409         List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
410         if (availableServiceInfos.isEmpty()) {
411             return null;
412         }
413         BoundServices highPriorityService = availableServiceInfos.get(0);
414         availableServiceInfos.remove(0);
415         for (BoundServices availableServiceInfo: availableServiceInfos) {
416             if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
417                 highPriorityService = availableServiceInfo;
418             }
419         }
420         return highPriorityService;
421     }
422
423     public static void installVlanFlow(BigInteger dpId, long portNo, Interface iface,
424                                        WriteTransaction t, List<MatchInfo> matches, int lportTag) {
425         int vlanId = 0;
426         boolean isVlanTransparent = false;
427         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
428         if(l2vlan != null){
429             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
430             isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
431         }
432         int instructionKey = 0;
433         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO, isExternal(iface));
434         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
435         List<Instruction> instructions = new ArrayList<>();
436         if (vlanId != 0 && !isVlanTransparent) {
437             instructions.add(MDSALUtil.buildAndGetPopVlanActionInstruction(lportTag, instructionKey++));
438         }
439         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
440         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
441         int priority =  isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
442         String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
443         Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
444                 NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
445         installFlow(dpId, ingressFlow, t);
446     }
447
448     public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
449         return String.format("%d:%s:%s", tableId, dpnId, infName);
450     }
451
452     public static void removeIngressFlow(String interfaceName, BigInteger dpId, WriteTransaction t) {
453         if(dpId == null){
454             return;
455         }
456         LOG.debug("Removing Ingress Flows for {}", interfaceName);
457         String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
458         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
459         Node nodeDpn = buildInventoryDpnNode(dpId);
460         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
461                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
462                 .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
463
464         t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
465     }
466
467     private static boolean isExternal(Interface iface) {
468         if (iface == null) {
469             return false;
470         }
471         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
472         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
473     }
474 }