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